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