001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements. See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache license, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License. You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the license for the specific language governing permissions and
015     * limitations under the license.
016     */
017    package org.apache.logging.log4j.core.helpers;
018    
019    
020    /**
021     * Utility class for transforming strings.
022     */
023    public final class Transform {
024    
025        private static final String CDATA_START = "<![CDATA[";
026        private static final String CDATA_END = "]]>";
027        private static final String CDATA_PSEUDO_END = "]]&gt;";
028        private static final String CDATA_EMBEDED_END = CDATA_END + CDATA_PSEUDO_END + CDATA_START;
029        private static final int CDATA_END_LEN = CDATA_END.length();
030    
031        private Transform() {
032        }
033    
034        /**
035         * This method takes a string which may contain HTML tags (ie,
036         * &lt;b&gt;, &lt;table&gt;, etc) and replaces any
037         * '<',  '>' , '&' or '"'
038         * characters with respective predefined entity references.
039         *
040         * @param input The text to be converted.
041         * @return The input string with the special characters replaced.
042         */
043        public static String escapeTags(final String input) {
044            //Check if the string is null, zero length or devoid of special characters
045            // if so, return what was sent in.
046    
047            if (input == null
048                || input.length() == 0
049                || (input.indexOf('"') == -1 &&
050                input.indexOf('&') == -1 &&
051                input.indexOf('<') == -1 &&
052                input.indexOf('>') == -1)) {
053                return input;
054            }
055    
056            //Use a StringBuffer in lieu of String concatenation -- it is
057            //much more efficient this way.
058    
059            final StringBuilder buf = new StringBuilder(input.length() + 6);
060            char ch = ' ';
061    
062            final int len = input.length();
063            for (int i = 0; i < len; i++) {
064                ch = input.charAt(i);
065                if (ch > '>') {
066                    buf.append(ch);
067                } else if (ch == '<') {
068                    buf.append("&lt;");
069                } else if (ch == '>') {
070                    buf.append("&gt;");
071                } else if (ch == '&') {
072                    buf.append("&amp;");
073                } else if (ch == '"') {
074                    buf.append("&quot;");
075                } else {
076                    buf.append(ch);
077                }
078            }
079            return buf.toString();
080        }
081    
082        /**
083         * Ensures that embeded CDEnd strings (]]>) are handled properly
084         * within message, NDC and throwable tag text.
085         *
086         * @param buf StringBuffer holding the XML data to this point.  The
087         *            initial CDStart (<![CDATA[) and final CDEnd (]]>) of the CDATA
088         *            section are the responsibility of the calling method.
089         * @param str The String that is inserted into an existing CDATA Section within buf.
090         */
091        public static void appendEscapingCDATA(final StringBuilder buf, final String str) {
092            if (str != null) {
093                int end = str.indexOf(CDATA_END);
094                if (end < 0) {
095                    buf.append(str);
096                } else {
097                    int start = 0;
098                    while (end > -1) {
099                        buf.append(str.substring(start, end));
100                        buf.append(CDATA_EMBEDED_END);
101                        start = end + CDATA_END_LEN;
102                        if (start < str.length()) {
103                            end = str.indexOf(CDATA_END, start);
104                        } else {
105                            return;
106                        }
107                    }
108                    buf.append(str.substring(start));
109                }
110            }
111        }
112    }