001 /*
002 // $Id: //open/util/resgen/src/org/eigenbase/xom/StringEscaper.java#6 $
003 // Package org.eigenbase.xom is an XML Object Mapper.
004 // Copyright (C) 2005-2005 The Eigenbase Project
005 // Copyright (C) 2005-2005 Disruptive Tech
006 // Copyright (C) 2005-2005 LucidEra, Inc.
007 // Portions Copyright (C) 2000-2005 Kana Software, Inc. and others.
008 //
009 // This library is free software; you can redistribute it and/or modify it
010 // under the terms of the GNU Lesser General Public License as published by the
011 // Free Software Foundation; either version 2 of the License, or (at your
012 // option) any later version approved by The Eigenbase Project.
013 //
014 // This library is distributed in the hope that it will be useful,
015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
017 // GNU Lesser General Public License for more details.
018 //
019 // You should have received a copy of the GNU Lesser General Public License
020 // along with this library; if not, write to the Free Software
021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
022 */
023
024 package org.eigenbase.xom;
025 import java.util.*;
026
027 /**
028 * <p><code>StringEscaper</code> is a utility for replacing special characters
029 * with escape sequences in strings. Initially, a StringEscaper starts out as
030 * an identity transform in the "mutable" state. Call defineEscape as many
031 * times as necessary to set up mappings, and then call makeImmutable() before
032 * using appendEscapedString to actually apply the defined transform. Or, use one of
033 * the global mappings pre-defined here.</p>
034 **/
035 public class StringEscaper implements Cloneable
036 {
037 private ArrayList translationVector;
038 private String [] translationTable;
039
040 public static StringEscaper xmlEscaper;
041 public static StringEscaper xmlNumericEscaper;
042 public static StringEscaper htmlEscaper;
043 public static StringEscaper urlArgEscaper;
044 public static StringEscaper urlEscaper;
045
046 /**
047 * Identity transform
048 */
049 public StringEscaper()
050 {
051 translationVector = new ArrayList();
052 }
053
054 /**
055 * Map character "from" to escape sequence "to"
056 */
057 public void defineEscape(char from,String to)
058 {
059 int i = (int) from;
060 if (i >= translationVector.size()) {
061 // Extend list by adding the requisite number of nulls.
062 final int count = i + 1 - translationVector.size();
063 translationVector.addAll(
064 new AbstractList() {
065 public Object get(int index) {
066 return null;
067 }
068
069 public int size() {
070 return count;
071 }
072 });
073 }
074 translationVector.set(i, to);
075 }
076
077 /**
078 * Call this before attempting to escape strings; after this,
079 * defineEscape may not be called again.
080 */
081 public void makeImmutable()
082 {
083 translationTable =
084 (String[]) translationVector.toArray(
085 new String[translationVector.size()]);
086 translationVector = null;
087 }
088
089 /**
090 * Apply an immutable transformation to the given string.
091 */
092 public String escapeString(String s)
093 {
094 StringBuffer sb = null;
095 int n = s.length();
096 for (int i = 0; i < n; i++) {
097 char c = s.charAt(i);
098 String escape;
099 // codes >= 128 (e.g. Euro sign) are always escaped
100 if (c > 127) {
101 escape = "&#" + Integer.toString(c) + ";";
102 } else if (c >= translationTable.length) {
103 escape = null;
104 } else {
105 escape = translationTable[c];
106 }
107 if (escape == null) {
108 if (sb != null) {
109 sb.append(c);
110 }
111 } else {
112 if (sb == null) {
113 sb = new StringBuffer(n * 2);
114 sb.append(s.substring(0, i));
115 }
116 sb.append(escape);
117 }
118 }
119
120 if (sb == null) {
121 return s;
122 } else {
123 return sb.toString();
124 }
125 }
126
127 /**
128 * Apply an immutable transformation to the given string, writing the
129 * results to a string buffer.
130 */
131 public void appendEscapedString(String s, StringBuffer sb)
132 {
133 int n = s.length();
134 for (int i = 0; i < n; i++) {
135 char c = s.charAt(i);
136 String escape;
137 if (c >= translationTable.length) {
138 escape = null;
139 } else {
140 escape = translationTable[c];
141 }
142 if (escape == null) {
143 sb.append(c);
144 } else {
145 sb.append(escape);
146 }
147 }
148 }
149
150 protected Object clone()
151 {
152 StringEscaper clone = new StringEscaper();
153 if (translationVector != null) {
154 clone.translationVector = new ArrayList(translationVector);
155 }
156 if (translationTable != null) {
157 clone.translationTable = (String[]) translationTable.clone();
158 }
159 return clone;
160 }
161
162 /**
163 * Create a mutable escaper from an existing escaper, which may
164 * already be immutable.
165 */
166 public StringEscaper getMutableClone()
167 {
168 StringEscaper clone = (StringEscaper) clone();
169 if (clone.translationVector == null) {
170 clone.translationVector =
171 new ArrayList(Arrays.asList(clone.translationTable));
172 clone.translationTable = null;
173 }
174 return clone;
175 }
176
177 static
178 {
179 htmlEscaper = new StringEscaper();
180 htmlEscaper.defineEscape('&', "&");
181 htmlEscaper.defineEscape('"', """);
182 // htmlEscaper.defineEscape('\'',"'");
183 htmlEscaper.defineEscape('\'', "'");
184 htmlEscaper.defineEscape('<', "<");
185 htmlEscaper.defineEscape('>', ">");
186
187 xmlNumericEscaper = new StringEscaper();
188 xmlNumericEscaper.defineEscape('&',"&");
189 xmlNumericEscaper.defineEscape('"',""");
190 xmlNumericEscaper.defineEscape('\'',"'");
191 xmlNumericEscaper.defineEscape('<',"<");
192 xmlNumericEscaper.defineEscape('>',">");
193
194 urlArgEscaper = new StringEscaper();
195 urlArgEscaper.defineEscape('?', "%3f");
196 urlArgEscaper.defineEscape('&', "%26");
197 urlEscaper = urlArgEscaper.getMutableClone();
198 urlEscaper.defineEscape('%', "%%");
199 urlEscaper.defineEscape('"', "%22");
200 urlEscaper.defineEscape('\r', "+");
201 urlEscaper.defineEscape('\n', "+");
202 urlEscaper.defineEscape(' ', "+");
203 urlEscaper.defineEscape('#', "%23");
204
205 htmlEscaper.makeImmutable();
206 xmlEscaper = htmlEscaper;
207 xmlNumericEscaper.makeImmutable();
208 urlArgEscaper.makeImmutable();
209 urlEscaper.makeImmutable();
210 }
211
212 }
213
214 // End StringEscaper.java