1 /* 2 * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.xml.internal.stream.writers; 27 28 import java.io.FileWriter; 29 import java.io.IOException; 30 import java.io.OutputStreamWriter; 31 import java.io.Writer; 32 import java.nio.charset.Charset; 33 import java.nio.charset.CharsetEncoder; 34 import com.sun.org.apache.xerces.internal.util.XMLChar; 35 import com.sun.org.apache.xerces.internal.utils.SecuritySupport; 36 37 /** 38 * Implements common xml writer functions. 39 * 40 * @author Neeraj Bajaj,K.Venugopal Sun Microsystems. 41 */ 42 43 public class WriterUtility { 44 45 46 public static final String START_COMMENT = "<!--"; 47 public static final String END_COMMENT = "-->"; 48 public static final String DEFAULT_ENCODING = " encoding=\"utf-8\""; 49 public static final String DEFAULT_XMLDECL ="<?xml version=\"1.0\" ?>"; 50 public static final String DEFAULT_XML_VERSION ="1.0"; 51 public static final char CLOSE_START_TAG = '>'; 52 public static final char OPEN_START_TAG = '<'; 53 public static final String OPEN_END_TAG ="</"; 54 public static final char CLOSE_END_TAG = '>'; 55 public static final String START_CDATA = "<![CDATA["; 56 public static final String END_CDATA = "]]>"; 57 public static final String CLOSE_EMPTY_ELEMENT = "/>"; 58 public static final String SPACE = " "; 59 public static final String UTF_8 = "utf-8"; 60 61 static final boolean DEBUG_XML_CONTENT = false; 62 63 /**XXX: This feature is only used when writing element content values. 64 * default value is 'true' however, if the feature is set to false 65 * characters wont be escaped. 66 * This feature has no effect when writing Attribute values, character would still be escaped. 67 * I can't think of any reason why this would be useful when writing attribute values. 68 * However, this can be reconsidered if there is any usecase. 69 */ 70 boolean fEscapeCharacters = true ; 71 72 /** Writer object*/ 73 Writer fWriter = null; 74 75 //CharsetEncoder 76 CharsetEncoder fEncoder ; 77 78 public WriterUtility(){ 79 fEncoder = getDefaultEncoder(); 80 } 81 82 83 /** Creates a new instance of WriterUtility */ 84 public WriterUtility(Writer writer) { 85 fWriter = writer; 86 if(writer instanceof OutputStreamWriter){ 87 String charset = ((OutputStreamWriter)writer).getEncoding(); 88 if(charset != null){ 89 fEncoder = Charset.forName(charset).newEncoder(); 90 } 91 }else if(writer instanceof FileWriter){ 92 String charset = ((FileWriter)writer).getEncoding(); 93 if(charset != null){ 94 fEncoder = Charset.forName(charset).newEncoder(); 95 } 96 } 97 else{ 98 //attempt to retreive default fEncoderoder 99 fEncoder = getDefaultEncoder(); 100 } 101 } 102 103 /** 104 * sets the writer object 105 * @param writer file to write into 106 */ 107 public void setWriter(Writer writer){ 108 fWriter = writer; 109 } 110 111 public void setEscapeCharacters(boolean escape){ 112 fEscapeCharacters = escape ; 113 } 114 115 public boolean getEscapeCharacters(){ 116 return fEscapeCharacters; 117 } 118 119 /** 120 * writes xml content (characters and element content 121 * @param content 122 */ 123 public void writeXMLContent(char[] content, int start, int length) throws IOException{ 124 writeXMLContent(content, start, length, getEscapeCharacters()); 125 } 126 127 /** 128 * writes xml content (characters and element content 129 * @param content 130 */ 131 private void writeXMLContent(char[] content, int start, int length, boolean escapeCharacter) throws IOException{ 132 if(DEBUG_XML_CONTENT){ 133 System.out.println("content to write is " + new String(content, start, length)); 134 } 135 int index; 136 char ch; 137 int sc; 138 final int end = start + length ; 139 //define startWritePos to track the position from where the character array data needs to be written 140 //initialize this variable to start pos. indicating that no data has been written 141 int startWritePos = start; 142 143 for ( index = start ; index < end ; index++ ) { 144 ch = content[ index ]; 145 146 if(fEncoder != null && !fEncoder.canEncode(ch)){ 147 //- write the data to the point we get this character 148 fWriter.write(content, startWritePos, index - startWritePos ); 149 150 //escape this character 151 fWriter.write( "&#x" ); 152 fWriter.write(Integer.toHexString(ch)); 153 fWriter.write( ';' ); 154 //increase the startWritePos by 1 indicating that next write should start from 155 //one position ahead 156 startWritePos = index + 1; 157 158 } 159 if(DEBUG_XML_CONTENT){ 160 System.out.println("startWritePos = " + startWritePos); 161 System.out.println("index = " + index); 162 System.out.println("start = " + start); 163 System.out.println("end = " + end); 164 } 165 166 switch(ch){ 167 case '<' :{ 168 if(escapeCharacter){ 169 //this character needs to be escaped, write the data from the last write pos 170 fWriter.write(content, startWritePos, index - startWritePos); 171 fWriter.write("<"); 172 if(DEBUG_XML_CONTENT){ 173 System.out.print(new String(content, startWritePos, index - startWritePos)); 174 System.out.println("<"); 175 } 176 //increase the startWritePos by 1 indicating that next write should start from 177 //one position ahead 178 startWritePos = index + 1; 179 } 180 break; 181 } 182 case '&' :{ 183 if(escapeCharacter){ 184 //this character needs to be escaped, write the data from the last write pos 185 fWriter.write(content, startWritePos, index - startWritePos); 186 fWriter.write("&"); 187 if(DEBUG_XML_CONTENT){ 188 System.out.print(new String(content,startWritePos, index - startWritePos)); 189 System.out.println("&"); 190 } 191 //increase the startWritePos by 1 indicating that next write should start from 192 //one position ahead 193 startWritePos = index + 1; 194 } 195 break; 196 } 197 198 case '>': { 199 if(escapeCharacter){ 200 //this character needs to be escaped, write the data from the last write pos 201 fWriter.write(content, startWritePos, index - startWritePos); 202 fWriter.write(">"); 203 if(DEBUG_XML_CONTENT){ 204 System.out.print(new String(content,startWritePos, index - startWritePos)); 205 System.out.println(">"); 206 } 207 //increase the startWritePos by 1 indicating that next write should start from 208 //one position ahead 209 startWritePos = index + 1; 210 } 211 break; 212 } 213 } 214 } 215 if(DEBUG_XML_CONTENT){ 216 System.out.println("out of the loop, writing " + new String(content, startWritePos, end - startWritePos)); 217 } 218 //write any pending data 219 fWriter.write(content, startWritePos, end - startWritePos); 220 } 221 222 /** 223 * writes xml content (characters and element content 224 * @param content 225 */ 226 public void writeXMLContent(String content) throws IOException{ 227 if(content == null || content.length() == 0) return ; 228 writeXMLContent(content.toCharArray(), 0, content.length()); 229 } 230 231 232 /** 233 * Write Attribute value to the underlying stream. 234 * 235 * @param value 236 */ 237 238 public void writeXMLAttributeValue(String value)throws IOException{ 239 writeXMLContent(value.toCharArray(), 0, value.length(), true); 240 } 241 242 private CharsetEncoder getDefaultEncoder(){ 243 try{ 244 String encoding = SecuritySupport.getSystemProperty("file.encoding"); 245 if(encoding != null){ 246 return Charset.forName(encoding).newEncoder(); 247 } 248 } 249 catch(Exception ex){ 250 //for any exception thrown , catch and continue 251 } 252 return null; 253 } 254 }