1.1 --- a/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/output/XMLStreamWriterOutput.java Tue May 16 13:28:58 2017 -0700 1.2 +++ b/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/output/XMLStreamWriterOutput.java Sun Jun 18 23:18:45 2017 +0100 1.3 @@ -1,5 +1,5 @@ 1.4 /* 1.5 - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. 1.6 + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. 1.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.8 * 1.9 * This code is free software; you can redistribute it and/or modify it 1.10 @@ -26,15 +26,16 @@ 1.11 package com.sun.xml.internal.bind.v2.runtime.output; 1.12 1.13 import java.io.IOException; 1.14 +import java.io.Writer; 1.15 import java.lang.reflect.Constructor; 1.16 1.17 import javax.xml.stream.XMLStreamException; 1.18 import javax.xml.stream.XMLStreamWriter; 1.19 1.20 +import com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler; 1.21 import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl; 1.22 import com.sun.xml.internal.bind.v2.runtime.XMLSerializer; 1.23 1.24 -import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl; 1.25 import org.xml.sax.SAXException; 1.26 1.27 /** 1.28 @@ -53,7 +54,7 @@ 1.29 * Creates a new {@link XmlOutput} from a {@link XMLStreamWriter}. 1.30 * This method recognizes an FI StAX writer. 1.31 */ 1.32 - public static XmlOutput create(XMLStreamWriter out, JAXBContextImpl context) { 1.33 + public static XmlOutput create(XMLStreamWriter out, JAXBContextImpl context, CharacterEscapeHandler escapeHandler) { 1.34 // try optimized path 1.35 final Class writerClass = out.getClass(); 1.36 if (writerClass==FI_STAX_WRITER_CLASS) { 1.37 @@ -69,17 +70,26 @@ 1.38 } 1.39 } 1.40 1.41 + CharacterEscapeHandler xmlStreamEscapeHandler = escapeHandler != null ? 1.42 + escapeHandler : NewLineEscapeHandler.theInstance; 1.43 + 1.44 // otherwise the normal writer. 1.45 - return new XMLStreamWriterOutput(out); 1.46 + return new XMLStreamWriterOutput(out, xmlStreamEscapeHandler); 1.47 } 1.48 1.49 1.50 private final XMLStreamWriter out; 1.51 1.52 + private final CharacterEscapeHandler escapeHandler; 1.53 + 1.54 + private final XmlStreamOutWriterAdapter writerWrapper; 1.55 + 1.56 protected final char[] buf = new char[256]; 1.57 1.58 - protected XMLStreamWriterOutput(XMLStreamWriter out) { 1.59 + protected XMLStreamWriterOutput(XMLStreamWriter out, CharacterEscapeHandler escapeHandler) { 1.60 this.out = out; 1.61 + this.escapeHandler = escapeHandler; 1.62 + this.writerWrapper = new XmlStreamOutWriterAdapter(out); 1.63 } 1.64 1.65 // not called if we are generating fragments 1.66 @@ -137,7 +147,7 @@ 1.67 public void text(String value, boolean needsSeparatingWhitespace) throws IOException, SAXException, XMLStreamException { 1.68 if(needsSeparatingWhitespace) 1.69 out.writeCharacters(" "); 1.70 - out.writeCharacters(value); 1.71 + escapeHandler.escape(value.toCharArray(), 0, value.length(), false, writerWrapper); 1.72 } 1.73 1.74 public void text(Pcdata value, boolean needsSeparatingWhitespace) throws IOException, SAXException, XMLStreamException { 1.75 @@ -207,4 +217,82 @@ 1.76 } 1.77 } 1.78 1.79 + 1.80 + /** 1.81 + * Performs character escaping only for new lines. 1.82 + */ 1.83 + private static class NewLineEscapeHandler implements CharacterEscapeHandler { 1.84 + 1.85 + public static final NewLineEscapeHandler theInstance = new NewLineEscapeHandler(); 1.86 + 1.87 + @Override 1.88 + public void escape(char[] ch, int start, int length, boolean isAttVal, Writer out) throws IOException { 1.89 + int limit = start+length; 1.90 + int lastEscaped = start; 1.91 + 1.92 + for (int i = start; i < limit; i++) { 1.93 + char c = ch[i]; 1.94 + if (c == '\r' || c == '\n') { 1.95 + if (i != lastEscaped) { 1.96 + out.write(ch, lastEscaped, i - lastEscaped); 1.97 + } 1.98 + lastEscaped = i + 1; 1.99 + if (out instanceof XmlStreamOutWriterAdapter) { 1.100 + try { 1.101 + ((XmlStreamOutWriterAdapter)out).writeEntityRef("#x" + Integer.toHexString(c)); 1.102 + } catch (XMLStreamException e) { 1.103 + throw new IOException("Error writing xml stream", e); 1.104 + } 1.105 + } else { 1.106 + out.write("&#x"); 1.107 + out.write(Integer.toHexString(c)); 1.108 + out.write(';'); 1.109 + } 1.110 + } 1.111 + } 1.112 + if (lastEscaped != limit) { 1.113 + out.write(ch, lastEscaped, length - lastEscaped); 1.114 + } 1.115 + } 1.116 + } 1.117 + 1.118 + private static final class XmlStreamOutWriterAdapter extends Writer { 1.119 + 1.120 + private final XMLStreamWriter writer; 1.121 + 1.122 + private XmlStreamOutWriterAdapter(XMLStreamWriter writer) { 1.123 + this.writer = writer; 1.124 + } 1.125 + 1.126 + @Override 1.127 + public void write(char[] cbuf, int off, int len) throws IOException { 1.128 + try { 1.129 + writer.writeCharacters(cbuf, off, len); 1.130 + } catch (XMLStreamException e) { 1.131 + throw new IOException("Error writing XML stream", e); 1.132 + } 1.133 + } 1.134 + 1.135 + public void writeEntityRef(String entityReference) throws XMLStreamException { 1.136 + writer.writeEntityRef(entityReference); 1.137 + } 1.138 + 1.139 + @Override 1.140 + public void flush() throws IOException { 1.141 + try { 1.142 + writer.flush(); 1.143 + } catch (XMLStreamException e) { 1.144 + throw new IOException("Error flushing XML stream", e); 1.145 + } 1.146 + } 1.147 + 1.148 + @Override 1.149 + public void close() throws IOException { 1.150 + try { 1.151 + writer.close(); 1.152 + } catch (XMLStreamException e) { 1.153 + throw new IOException("Error closing XML stream", e); 1.154 + } 1.155 + } 1.156 + } 1.157 }