/* * File : XUXmlWriter.java * Created : 23-Oct-2003 * By : parg * * Azureus - a Java Bittorrent client * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details ( see the LICENSE file ). * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.gudy.azureus2.core3.xml.util; /** * @author parg */ import java.io.*; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Map; import org.gudy.azureus2.core3.util.*; public class XUXmlWriter { private static final int INDENT_AMOUNT = 4; private String current_indent_string; private PrintWriter writer; private boolean generic_simple; protected XUXmlWriter() { resetIndent(); } protected XUXmlWriter( OutputStream _output_stream ) { setOutputStream( _output_stream ); resetIndent(); } protected void setOutputStream( OutputStream _output_stream ) { try{ writer = new PrintWriter( new OutputStreamWriter(_output_stream , Constants.DEFAULT_ENCODING )); }catch( UnsupportedEncodingException e ){ // Debug.printStackTrace( e ); writer = new PrintWriter( _output_stream ); } } protected void setOutputWriter( Writer _writer ) { if ( _writer instanceof PrintWriter ){ writer = (PrintWriter)_writer; }else{ writer = new PrintWriter( _writer ); } } protected void setGenericSimple( boolean simple ) { generic_simple = simple; } protected void writeTag( String tag, String content ) { writeLineRaw( "<" + tag + ">" + escapeXML( content ) + "</" + tag + ">" ); } protected void writeTag( String tag, long content ) { writeLineRaw( "<" + tag + ">" + content + "</" + tag + ">" ); } protected void writeTag( String tag, boolean content ) { writeLineRaw( "<" + tag + ">" + (content?"YES":"NO") + "</" + tag + ">" ); } protected void writeLineRaw( String str ) { writer.println( current_indent_string + str ); } protected void writeLineEscaped( String str ) { writer.println( current_indent_string + escapeXML(str)); } protected void resetIndent() { current_indent_string = ""; } protected void indent() { for (int i=0;i<INDENT_AMOUNT;i++){ current_indent_string += " "; } } protected void exdent() { if ( current_indent_string.length() >= INDENT_AMOUNT ){ current_indent_string = current_indent_string.substring(0,current_indent_string.length()-INDENT_AMOUNT); }else{ current_indent_string = ""; } } public static String escapeXML( String str ) { if ( str == null ){ return( "" ); } str = str.replaceAll( "&", "&" ); str = str.replaceAll( ">", ">" ); str = str.replaceAll( "<", "<" ); str = str.replaceAll( "\"", """ ); str = str.replaceAll( "'", "'" ); str = str.replaceAll( "--", "--" ); char[] chars = str.toCharArray(); // eliminate chars not supported by XML for ( int i=0;i<chars.length;i++){ int c = (int)chars[i]; if ( ( c <= 31 ) || ( c >= 127 && c <= 159 ) || !Character.isDefined( c )){ chars[i] = '?'; } } return( new String( chars )); } public static String unescapeXML( String str ) { if ( str == null ){ return( "" ); } str = str.replaceAll( ">", ">" ); str = str.replaceAll( "<", "<" ); str = str.replaceAll( """, "\"" ); str = str.replaceAll( "'", "'" ); str = str.replaceAll( "--", "--" ); str = str.replaceAll( "&", "&" ); return( str ); } public static String[] splitWithEscape( String str, char delim ) { List<String> res = new ArrayList<String>(); String current = ""; char[] chars = str.toCharArray(); for (int i=0;i<chars.length;i++){ char c = chars[i]; if ( c == '\\' && i+1<chars.length && chars[i+1] == delim ){ current += delim; i++; }else if ( c == delim ){ if ( current.length() > 0 ){ res.add( current ); current = ""; } }else{ current += c; } } if ( current.length() > 0 ){ res.add( current ); } return( res.toArray( new String[ res.size() ])); } protected void flushOutputStream() { if ( writer != null ){ writer.flush(); } } protected void closeOutputStream() { if ( writer != null ){ writer.flush(); writer.close(); writer = null; } } // generic Map encoder protected void writeGenericMapEntry( String name, Object value ) { if ( generic_simple ){ name = name.replace(' ', '_' ).toUpperCase(); writeLineRaw( "<" + name + ">" ); try{ indent(); writeGeneric( value ); }finally{ exdent(); } writeLineRaw( "</" + name + ">" ); }else{ writeLineRaw( "<KEY name=\"" + escapeXML( name ) + "\">"); try{ indent(); writeGeneric( value ); }finally{ exdent(); } writeLineRaw( "</KEY>"); } } protected void writeGeneric( Object obj ) { if ( obj instanceof Map ){ writeGeneric((Map)obj); }else if( obj instanceof List ){ writeGeneric((List)obj); }else if ( obj instanceof String ){ writeGeneric((String)obj ); }else if ( obj instanceof byte[] ){ writeGeneric((byte[])obj); }else{ writeGeneric((Long)obj); } } protected void writeGeneric( Map map ) { writeLineRaw( "<MAP>" ); try{ indent(); Iterator it = map.keySet().iterator(); while(it.hasNext()){ String key = (String)it.next(); writeGenericMapEntry( key, map.get( key )); } }finally{ exdent(); } writeLineRaw( "</MAP>" ); } protected void writeGeneric( List list ) { writeLineRaw( "<LIST>" ); try{ indent(); for (int i=0;i<list.size();i++){ writeGeneric( list.get(i)); } }finally{ exdent(); } writeLineRaw( "</LIST>" ); } protected void writeGeneric( byte[] bytes ) { if ( generic_simple ){ try{ writeLineRaw( escapeXML( new String(bytes, "UTF-8" ))); }catch( Throwable e ){ e.printStackTrace(); } }else{ writeTag( "BYTES", encodeBytes( bytes )); } } protected void writeGeneric( String str ) { if ( generic_simple ){ try{ writeLineRaw( escapeXML( str )); }catch( Throwable e ){ e.printStackTrace(); } }else{ writeTag( "STRING", str ); } } protected void writeGeneric( Long l ) { if ( generic_simple ){ writeLineRaw( l.toString()); }else{ writeTag( "LONG", ""+l ); } } protected void writeTag( String tag, byte[] content ) { writeLineRaw( "<" + tag + ">" + encodeBytes( content ) + "</" + tag + ">" ); } protected void writeLocalisableTag( String tag, byte[] content ) { boolean use_bytes = true; String utf_string = null; try{ utf_string = new String(content,Constants.DEFAULT_ENCODING); if ( Arrays.equals( content, utf_string.getBytes( Constants.DEFAULT_ENCODING))){ use_bytes = false; } }catch( UnsupportedEncodingException e ){ } writeLineRaw( "<" + tag + " encoding=\""+(use_bytes?"bytes":"utf8") + "\">" + (use_bytes?encodeBytes( content ):escapeXML(utf_string)) + "</" + tag + ">" ); } protected String encodeBytes( byte[] bytes ) { String data = ByteFormatter.nicePrint( bytes, true ); return( data ); /* try{ return( URLEncoder.encode(new String( bytes, Constants.DEFAULT_ENCODING ), Constants.DEFAULT_ENCODING)); }catch( UnsupportedEncodingException e ){ throw( new TOTorrentException( "TOTorrentXMLSerialiser: unsupported encoding for '" + new String(bytes) + "'", TOTorrentException.RT_UNSUPPORTED_ENCODING)); } */ } protected String getUTF( byte[] bytes ) { try{ return( new String(bytes,Constants.DEFAULT_ENCODING)); }catch( UnsupportedEncodingException e ){ // Debug.printStackTrace( e ); return( "" ); } } }