FileDocCategorySizeDatePackage
TextUtil.javaAPI DocExample8573Mon Jul 23 13:26:50 BST 2007org.apache.struts2.views.util

TextUtil.java

/*
 * $Id: TextUtil.java 515882 2007-03-08 01:33:04Z rgielen $
 *
 * Copyright 2006 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.struts2.views.util;


/**
 * This class handles HTML escaping of text.
 * It was written and optimized to be as fast as possible.
 *
 */
public class TextUtil {

    protected static final int MAX_LENGTH = 300;

    /**
     * We use arrays of char in the lookup table because it is faster
     * appending this to a StringBuffer than appending a String
     */
    protected static final char[][] _stringChars = new char[MAX_LENGTH][];

    static {
        // Initialize the mapping table
        initMapping();
    }


    /**
     * Call escapeHTML(s, false)
     */
    public static final String escapeHTML(String s) {
        return escapeHTML(s, false);
    }

    /**
     * Escape HTML.
     *
     * @param s           string to be escaped
     * @param escapeEmpty if true, then empty string will be escaped.
     */
    public static final String escapeHTML(String s, boolean escapeEmpty) {
        int len = s.length();

        if (len == 0) {
            return s;
        }

        if (!escapeEmpty) {
            String trimmed = s.trim();

            if ((trimmed.length() == 0) || ("\"\"").equals(trimmed)) {
                return s;
            }
        }

        int i = 0;

        // First loop through String and check if escaping is needed at all
        // No buffers are copied at this time
        do {
            int index = s.charAt(i);

            if (index >= MAX_LENGTH) {
                if (index != 0x20AC) { // If not euro symbol

                    continue;
                }

                break;
            } else if (_stringChars[index] != null) {
                break;
            }
        } while (++i < len);

        // If the check went to the end with no escaping then i should be == len now
        // otherwise we must continue escaping for real
        if (i == len) {
            return s;
        }

        // We found a character to escape and broke out at position i
        // Now copy all characters before that to StringBuffer sb
        // Since a char[] will be used for copying we might as well get
        // a complete copy of it so that we can use array indexing instead of charAt
        StringBuffer sb = new StringBuffer(len + 40);
        char[] chars = new char[len];

        // Copy all chars from the String s to the chars buffer
        s.getChars(0, len, chars, 0);

        // Append the first i characters that we have checked to the resulting StringBuffer
        sb.append(chars, 0, i);

        int last = i;
        char[] subst;

        for (; i < len; i++) {
            char c = chars[i];
            int index = c;

            if (index < MAX_LENGTH) {
                subst = _stringChars[index];

                // It is faster to append a char[] than a String which is why we use this
                if (subst != null) {
                    if (i > last) {
                        sb.append(chars, last, i - last);
                    }

                    sb.append(subst);
                    last = i + 1;
                }
            }
            // Check if it is the euro symbol. This could be changed to check in a second lookup
            // table in case one wants to convert more characters in that area
            else if (index == 0x20AC) {
                if (i > last) {
                    sb.append(chars, last, i - last);
                }

                sb.append("€");
                last = i + 1;
            }
        }

        if (i > last) {
            sb.append(chars, last, i - last);
        }

        return sb.toString();
    }

    protected static void addMapping(int c, String txt, String[] strings) {
        strings[c] = txt;
    }

    protected static void initMapping() {
        String[] strings = new String[MAX_LENGTH];

        addMapping(0x22, """, strings); // "
        addMapping(0x26, "&", strings); // &
        addMapping(0x3c, "<", strings); // <
        addMapping(0x3e, ">", strings); // >

        addMapping(0xa1, "¡", strings); //
        addMapping(0xa2, "¢", strings); //
        addMapping(0xa3, "£", strings); //
        addMapping(0xa9, "©", strings); //
        addMapping(0xae, "®", strings); //
        addMapping(0xbf, "¿", strings); //

        addMapping(0xc0, "À", strings); //
        addMapping(0xc1, "Á", strings); //
        addMapping(0xc2, "Â", strings); //
        addMapping(0xc3, "Ã", strings); //
        addMapping(0xc4, "Ä", strings); //
        addMapping(0xc5, "Å", strings); //
        addMapping(0xc6, "Æ", strings); //
        addMapping(0xc7, "Ç", strings); //
        addMapping(0xc8, "È", strings); //
        addMapping(0xc9, "É", strings); //
        addMapping(0xca, "Ê", strings); //
        addMapping(0xcb, "Ë", strings); //
        addMapping(0xcc, "Ì", strings); //
        addMapping(0xcd, "Í", strings); //
        addMapping(0xce, "Î", strings); //
        addMapping(0xcf, "Ï", strings); //

        addMapping(0xd0, "Ð", strings); //
        addMapping(0xd1, "Ñ", strings); //
        addMapping(0xd2, "Ò", strings); //
        addMapping(0xd3, "Ó", strings); //
        addMapping(0xd4, "Ô", strings); //
        addMapping(0xd5, "Õ", strings); //
        addMapping(0xd6, "Ö", strings); //
        addMapping(0xd7, "×", strings); //
        addMapping(0xd8, "Ø", strings); //
        addMapping(0xd9, "Ù", strings); //
        addMapping(0xda, "Ú", strings); //
        addMapping(0xdb, "Û", strings); //
        addMapping(0xdc, "Ü", strings); //
        addMapping(0xdd, "Ý", strings); //
        addMapping(0xde, "Þ", strings); //
        addMapping(0xdf, "ß", strings); //

        addMapping(0xe0, "à", strings); //
        addMapping(0xe1, "á", strings); //
        addMapping(0xe2, "â", strings); //
        addMapping(0xe3, "ã", strings); //
        addMapping(0xe4, "ä", strings); //
        addMapping(0xe5, "å", strings); //
        addMapping(0xe6, "æ", strings); //
        addMapping(0xe7, "ç", strings); //
        addMapping(0xe8, "è", strings); //
        addMapping(0xe9, "é", strings); //
        addMapping(0xea, "ê", strings); //
        addMapping(0xeb, "ë", strings); //
        addMapping(0xec, "ì", strings); //
        addMapping(0xed, "í", strings); //
        addMapping(0xee, "î", strings); //
        addMapping(0xef, "ï", strings); //

        addMapping(0xf0, "ð", strings); //
        addMapping(0xf1, "ñ", strings); //
        addMapping(0xf2, "ò", strings); //
        addMapping(0xf3, "ó", strings); //
        addMapping(0xf4, "ô", strings); //
        addMapping(0xf5, "õ", strings); //
        addMapping(0xf6, "ö", strings); //
        addMapping(0xf7, "÷", strings); //
        addMapping(0xf8, "ø", strings); //
        addMapping(0xf9, "ù", strings); //
        addMapping(0xfa, "ú", strings); //
        addMapping(0xfb, "û", strings); //
        addMapping(0xfc, "ü", strings); //
        addMapping(0xfd, "ý", strings); //
        addMapping(0xfe, "þ", strings); //
        addMapping(0xff, "ÿ", strings); //

        for (int i = 0; i < strings.length; i++) {
            String str = strings[i];

            if (str != null) {
                _stringChars[i] = str.toCharArray();
            }
        }
    }
}