001: /*
002: * $Id: TextUtil.java 515882 2007-03-08 01:33:04Z rgielen $
003: *
004: * Copyright 2006 The Apache Software Foundation.
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018: package org.apache.struts2.views.util;
019:
020: /**
021: * This class handles HTML escaping of text.
022: * It was written and optimized to be as fast as possible.
023: *
024: */
025: public class TextUtil {
026:
027: protected static final int MAX_LENGTH = 300;
028:
029: /**
030: * We use arrays of char in the lookup table because it is faster
031: * appending this to a StringBuffer than appending a String
032: */
033: protected static final char[][] _stringChars = new char[MAX_LENGTH][];
034:
035: static {
036: // Initialize the mapping table
037: initMapping();
038: }
039:
040: /**
041: * Call escapeHTML(s, false)
042: */
043: public static final String escapeHTML(String s) {
044: return escapeHTML(s, false);
045: }
046:
047: /**
048: * Escape HTML.
049: *
050: * @param s string to be escaped
051: * @param escapeEmpty if true, then empty string will be escaped.
052: */
053: public static final String escapeHTML(String s, boolean escapeEmpty) {
054: int len = s.length();
055:
056: if (len == 0) {
057: return s;
058: }
059:
060: if (!escapeEmpty) {
061: String trimmed = s.trim();
062:
063: if ((trimmed.length() == 0) || ("\"\"").equals(trimmed)) {
064: return s;
065: }
066: }
067:
068: int i = 0;
069:
070: // First loop through String and check if escaping is needed at all
071: // No buffers are copied at this time
072: do {
073: int index = s.charAt(i);
074:
075: if (index >= MAX_LENGTH) {
076: if (index != 0x20AC) { // If not euro symbol
077:
078: continue;
079: }
080:
081: break;
082: } else if (_stringChars[index] != null) {
083: break;
084: }
085: } while (++i < len);
086:
087: // If the check went to the end with no escaping then i should be == len now
088: // otherwise we must continue escaping for real
089: if (i == len) {
090: return s;
091: }
092:
093: // We found a character to escape and broke out at position i
094: // Now copy all characters before that to StringBuffer sb
095: // Since a char[] will be used for copying we might as well get
096: // a complete copy of it so that we can use array indexing instead of charAt
097: StringBuffer sb = new StringBuffer(len + 40);
098: char[] chars = new char[len];
099:
100: // Copy all chars from the String s to the chars buffer
101: s.getChars(0, len, chars, 0);
102:
103: // Append the first i characters that we have checked to the resulting StringBuffer
104: sb.append(chars, 0, i);
105:
106: int last = i;
107: char[] subst;
108:
109: for (; i < len; i++) {
110: char c = chars[i];
111: int index = c;
112:
113: if (index < MAX_LENGTH) {
114: subst = _stringChars[index];
115:
116: // It is faster to append a char[] than a String which is why we use this
117: if (subst != null) {
118: if (i > last) {
119: sb.append(chars, last, i - last);
120: }
121:
122: sb.append(subst);
123: last = i + 1;
124: }
125: }
126: // Check if it is the euro symbol. This could be changed to check in a second lookup
127: // table in case one wants to convert more characters in that area
128: else if (index == 0x20AC) {
129: if (i > last) {
130: sb.append(chars, last, i - last);
131: }
132:
133: sb.append("€");
134: last = i + 1;
135: }
136: }
137:
138: if (i > last) {
139: sb.append(chars, last, i - last);
140: }
141:
142: return sb.toString();
143: }
144:
145: protected static void addMapping(int c, String txt, String[] strings) {
146: strings[c] = txt;
147: }
148:
149: protected static void initMapping() {
150: String[] strings = new String[MAX_LENGTH];
151:
152: addMapping(0x22, """, strings); // "
153: addMapping(0x26, "&", strings); // &
154: addMapping(0x3c, "<", strings); // <
155: addMapping(0x3e, ">", strings); // >
156:
157: addMapping(0xa1, "¡", strings); //
158: addMapping(0xa2, "¢", strings); //
159: addMapping(0xa3, "£", strings); //
160: addMapping(0xa9, "©", strings); //
161: addMapping(0xae, "®", strings); //
162: addMapping(0xbf, "¿", strings); //
163:
164: addMapping(0xc0, "À", strings); //
165: addMapping(0xc1, "Á", strings); //
166: addMapping(0xc2, "Â", strings); //
167: addMapping(0xc3, "Ã", strings); //
168: addMapping(0xc4, "Ä", strings); //
169: addMapping(0xc5, "Å", strings); //
170: addMapping(0xc6, "Æ", strings); //
171: addMapping(0xc7, "Ç", strings); //
172: addMapping(0xc8, "È", strings); //
173: addMapping(0xc9, "É", strings); //
174: addMapping(0xca, "Ê", strings); //
175: addMapping(0xcb, "Ë", strings); //
176: addMapping(0xcc, "Ì", strings); //
177: addMapping(0xcd, "Í", strings); //
178: addMapping(0xce, "Î", strings); //
179: addMapping(0xcf, "Ï", strings); //
180:
181: addMapping(0xd0, "Ð", strings); //
182: addMapping(0xd1, "Ñ", strings); //
183: addMapping(0xd2, "Ò", strings); //
184: addMapping(0xd3, "Ó", strings); //
185: addMapping(0xd4, "Ô", strings); //
186: addMapping(0xd5, "Õ", strings); //
187: addMapping(0xd6, "Ö", strings); //
188: addMapping(0xd7, "×", strings); //
189: addMapping(0xd8, "Ø", strings); //
190: addMapping(0xd9, "Ù", strings); //
191: addMapping(0xda, "Ú", strings); //
192: addMapping(0xdb, "Û", strings); //
193: addMapping(0xdc, "Ü", strings); //
194: addMapping(0xdd, "Ý", strings); //
195: addMapping(0xde, "Þ", strings); //
196: addMapping(0xdf, "ß", strings); //
197:
198: addMapping(0xe0, "à", strings); //
199: addMapping(0xe1, "á", strings); //
200: addMapping(0xe2, "â", strings); //
201: addMapping(0xe3, "ã", strings); //
202: addMapping(0xe4, "ä", strings); //
203: addMapping(0xe5, "å", strings); //
204: addMapping(0xe6, "æ", strings); //
205: addMapping(0xe7, "ç", strings); //
206: addMapping(0xe8, "è", strings); //
207: addMapping(0xe9, "é", strings); //
208: addMapping(0xea, "ê", strings); //
209: addMapping(0xeb, "ë", strings); //
210: addMapping(0xec, "ì", strings); //
211: addMapping(0xed, "í", strings); //
212: addMapping(0xee, "î", strings); //
213: addMapping(0xef, "ï", strings); //
214:
215: addMapping(0xf0, "ð", strings); //
216: addMapping(0xf1, "ñ", strings); //
217: addMapping(0xf2, "ò", strings); //
218: addMapping(0xf3, "ó", strings); //
219: addMapping(0xf4, "ô", strings); //
220: addMapping(0xf5, "õ", strings); //
221: addMapping(0xf6, "ö", strings); //
222: addMapping(0xf7, "÷", strings); //
223: addMapping(0xf8, "ø", strings); //
224: addMapping(0xf9, "ù", strings); //
225: addMapping(0xfa, "ú", strings); //
226: addMapping(0xfb, "û", strings); //
227: addMapping(0xfc, "ü", strings); //
228: addMapping(0xfd, "ý", strings); //
229: addMapping(0xfe, "þ", strings); //
230: addMapping(0xff, "ÿ", strings); //
231:
232: for (int i = 0; i < strings.length; i++) {
233: String str = strings[i];
234:
235: if (str != null) {
236: _stringChars[i] = str.toCharArray();
237: }
238: }
239: }
240: }
|