    001//  Copyright 2008, 2009, 2010 The Apache Software Foundation
    002//
    003// Licensed under the Apache License, Version 2.0 (the "License");
    004// you may not use this file except in compliance with the License.
    005// You may obtain a copy of the License at
    006//
    007//     http://www.apache.org/licenses/LICENSE-2.0
    008//
    009// Unless required by applicable law or agreed to in writing, software
    010// distributed under the License is distributed on an "AS IS" BASIS,
    011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    012// See the License for the specific language governing permissions and
    013// limitations under the License.
    014
    015package org.apache.tapestry5.dom;
    016
    017public abstract class AbstractMarkupModel implements MarkupModel
    018{
    019    private final boolean useApostropheForAttributes;
    020    private final char attributeQuoteChar;
    021
    022    protected AbstractMarkupModel(boolean useApostropheForAttributes)
    023    {
    024        this.useApostropheForAttributes = useApostropheForAttributes;
    025        this.attributeQuoteChar = useApostropheForAttributes ? '\'' : '"';
    026    }
    027
    028    public char getAttributeQuote()
    029    {
    030        return attributeQuoteChar;
    031    }
    032
    033    /**
    034     * Passes all characters but '&lt;', '&gt;' and '&amp;' through unchanged.
    035     */
    036    public String encode(String content)
    037    {
    038        int length = content.length();
    039
    040        StringBuilder builder = null;
    041
    042        for (int i = 0; i < length; i++)
    043        {
    044            char ch = content.charAt(i);
    045
    046            switch (ch)
    047            {
    048                case '<':
    049
    050                    if (builder == null)
    051                    {
    052                        builder = new StringBuilder(2 * length);
    053
    054                        builder.append(content.substring(0, i));
    055                    }
    056
    057                    builder.append("&lt;");
    058                    continue;
    059
    060                case '>':
    061
    062                    if (builder == null)
    063                    {
    064                        builder = new StringBuilder(2 * length);
    065
    066                        builder.append(content.substring(0, i));
    067                    }
    068
    069                    builder.append("&gt;");
    070                    continue;
    071
    072                case '&':
    073
    074                    if (builder == null)
    075                    {
    076                        builder = new StringBuilder(2 * length);
    077
    078                        builder.append(content.substring(0, i));
    079                    }
    080
    081                    builder.append("&amp;");
    082                    continue;
    083
    084                default:
    085
    086                    if (builder != null)
    087                        builder.append(ch);
    088            }
    089        }
    090
    091        return builder == null ? content : builder.toString();
    092    }
    093
    094    public void encodeQuoted(String content, StringBuilder builder)
    095    {
    096        assert content != null;
    097        int length = content.length(), tokenStart = 0, i = 0;
    098        builder.ensureCapacity(builder.length() + length);
    099        String delimiter;
    100        for (; i < length; i++)
    101        {
    102            char ch = content.charAt(i);
    103
    104            switch (ch)
    105            {
    106                case '<':
    107
    108                    delimiter = "&lt;";
    109                    break;
    110
    111                case '>':
    112
    113                    delimiter = "&gt;";
    114                    break;
    115
    116                case '&':
    117
    118                    delimiter = "&amp;";
    119                    break;
    120
    121                case '"':
    122
    123                    if (!useApostropheForAttributes)
    124                    {
    125                        delimiter = "&quot;";
    126                        break;
    127                    }
    128
    129                    continue;
    130
    131                case '\'':
    132
    133                    if (useApostropheForAttributes)
    134                    {
    135                        //TAP5-714
    136                        delimiter = "&#39;";
    137                        break;
    138                    }
    139
    140
    141                    continue;
    142
    143
    144                default:
    145
    146                    continue;
    147            }
    148
    149            if (tokenStart != i)
    150            {
    151                builder.append(content.subSequence(tokenStart, i));
    152            }
    153
    154            builder.append(delimiter);
    155
    156            tokenStart = i + 1;
    157        }
    158
    159        if (tokenStart != length)
    160        {
    161            builder.append(content.subSequence(tokenStart, length));
    162        }
    163    }
    164}