001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.io; 003 004import java.io.Closeable; 005import java.io.IOException; 006import java.io.PrintWriter; 007import java.util.HashMap; 008import java.util.Map; 009 010/** 011 * Helper class to use for xml outputting classes. 012 * 013 * @author imi 014 */ 015public class XmlWriter implements Closeable { 016 017 protected final PrintWriter out; 018 019 /** 020 * Constructs a new {@code XmlWriter}. 021 * @param out print writer 022 */ 023 public XmlWriter(PrintWriter out) { 024 this.out = out; 025 } 026 027 /** 028 * Flushes the stream. 029 */ 030 public void flush() { 031 if (out != null) { 032 out.flush(); 033 } 034 } 035 036 /** 037 * Encode the given string in XML1.0 format. 038 * Optimized to fast pass strings that don't need encoding (normal case). 039 * 040 * @param unencoded the unencoded input string 041 * @return XML1.0 string 042 */ 043 public static String encode(String unencoded) { 044 return encode(unencoded, false); 045 } 046 047 /** 048 * Encode the given string in XML1.0 format. 049 * Optimized to fast pass strings that don't need encoding (normal case). 050 * 051 * @param unencoded the unencoded input string 052 * @param keepApos true if apostrophe sign should stay as it is (in order to work around 053 * a Java bug that renders 054 * new JLabel("<html>&apos;</html>") 055 * literally as 6 character string, see #7558) 056 * @return XML1.0 string 057 */ 058 public static String encode(String unencoded, boolean keepApos) { 059 StringBuilder buffer = null; 060 if (unencoded != null) { 061 for (int i = 0; i < unencoded.length(); ++i) { 062 String encS = null; 063 if (!keepApos || unencoded.charAt(i) != '\'') { 064 encS = ENCODING.get(unencoded.charAt(i)); 065 } 066 if (encS != null) { 067 if (buffer == null) { 068 buffer = new StringBuilder(unencoded.substring(0, i)); 069 } 070 buffer.append(encS); 071 } else if (buffer != null) { 072 buffer.append(unencoded.charAt(i)); 073 } 074 } 075 } 076 return (buffer == null) ? unencoded : buffer.toString(); 077 } 078 079 /** 080 * The output writer to save the values to. 081 */ 082 private static final Map<Character, String> ENCODING = new HashMap<>(); 083 static { 084 ENCODING.put('<', "<"); 085 ENCODING.put('>', ">"); 086 ENCODING.put('"', """); 087 ENCODING.put('\'', "'"); 088 ENCODING.put('&', "&"); 089 ENCODING.put('\n', "
"); 090 ENCODING.put('\r', "
"); 091 ENCODING.put('\t', "	"); 092 } 093 094 @Override 095 public void close() throws IOException { 096 if (out != null) { 097 out.close(); 098 } 099 } 100}