| /* |
| * Copyright 2003-2007 the original author or authors. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package groovy.xml.streamingmarkupsupport; |
| |
| import java.io.IOException; |
| import java.io.OutputStreamWriter; |
| import java.io.Writer; |
| import java.nio.charset.Charset; |
| import java.nio.charset.CharsetEncoder; |
| |
| public class StreamingMarkupWriter extends Writer { |
| protected final Writer writer; |
| protected final String encoding; |
| protected final CharsetEncoder encoder; |
| protected boolean writingAttribute = false; |
| protected boolean haveHighSurrogate = false; |
| protected StringBuffer surrogatePair = new StringBuffer(2); |
| private final Writer escapedWriter = new Writer() { |
| /* (non-Javadoc) |
| * @see java.io.Writer#close() |
| */ |
| public void close() throws IOException { |
| StreamingMarkupWriter.this.close(); |
| } |
| |
| /* (non-Javadoc) |
| * @see java.io.Writer#flush() |
| */ |
| public void flush() throws IOException { |
| StreamingMarkupWriter.this.flush(); |
| } |
| |
| /* (non-Javadoc) |
| * @see java.io.Writer#write(int) |
| */ |
| public void write(final int c) throws IOException { |
| if (c == '<') { |
| StreamingMarkupWriter.this.writer.write("<"); |
| } else if (c == '>') { |
| StreamingMarkupWriter.this.writer.write(">"); |
| } else if (c == '&') { |
| StreamingMarkupWriter.this.writer.write("&"); |
| } else { |
| StreamingMarkupWriter.this.write(c); |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see java.io.Writer#write(char[], int, int) |
| */ |
| public void write(final char[] cbuf, int off, int len) throws IOException { |
| while (len-- > 0){ |
| write(cbuf[off++]); |
| } |
| } |
| |
| public void setWritingAttribute(final boolean writingAttribute) { |
| StreamingMarkupWriter.this.writingAttribute = writingAttribute; |
| } |
| |
| public Writer excaped() { |
| return escapedWriter; |
| } |
| |
| public Writer unescaped() { |
| return StreamingMarkupWriter.this; |
| } |
| }; |
| |
| public StreamingMarkupWriter(final Writer writer, final String encoding) { |
| this.writer = writer; |
| |
| if (encoding != null) { |
| this.encoding = encoding; |
| } else if (writer instanceof OutputStreamWriter) { |
| this.encoding = ((OutputStreamWriter)writer).getEncoding(); |
| } else { |
| this.encoding = "US-ASCII"; |
| } |
| |
| this.encoder = Charset.forName(this.encoding).newEncoder(); |
| } |
| |
| public StreamingMarkupWriter(final Writer writer) { |
| this(writer, null); |
| } |
| |
| /* (non-Javadoc) |
| * @see java.io.Writer#close() |
| */ |
| public void close() throws IOException { |
| this.writer.close(); |
| } |
| |
| /* (non-Javadoc) |
| * @see java.io.Writer#flush() |
| */ |
| public void flush() throws IOException { |
| this.writer.flush(); |
| } |
| |
| /* (non-Javadoc) |
| * @see java.io.Writer#write(int) |
| */ |
| public void write(final int c) throws IOException { |
| if (c >= 0XDC00 && c <= 0XDFFF) { |
| // Low surrogate |
| this.surrogatePair.append((char)c); |
| |
| if (this.encoder.canEncode(this.surrogatePair)) { |
| this.writer.write(this.surrogatePair.toString()); |
| } else { |
| this.writer.write("&#x"); |
| this.writer.write(Integer.toHexString(0X10000 + ((this.surrogatePair.charAt(0) & 0X3FF) << 10) + (c & 0X3FF))); |
| this.writer.write(';'); |
| } |
| |
| this.haveHighSurrogate = false; |
| this.surrogatePair.setLength(0); |
| } else { |
| if (this.haveHighSurrogate) { |
| this.haveHighSurrogate = false; |
| this.surrogatePair.setLength(0); |
| throw new IOException("High Surrogate not followed by Low Surrogate"); |
| } |
| |
| if (c >= 0XD800 && c <= 0XDBFF) { |
| // High surrogate |
| this.surrogatePair.append((char)c); |
| this.haveHighSurrogate = true; |
| |
| } else if (!this.encoder.canEncode((char)c)) { |
| this.writer.write("&#x"); |
| this.writer.write(Integer.toHexString(c)); |
| this.writer.write(';'); |
| } else if (c == '\'' && this.writingAttribute) { |
| this.writer.write("'"); |
| } else { |
| this.writer.write(c); |
| } |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see java.io.Writer#write(char[], int, int) |
| */ |
| public void write(final char[] cbuf, int off, int len) throws IOException { |
| while (len-- > 0){ |
| write(cbuf[off++]); |
| } |
| } |
| |
| public void setWritingAttribute(final boolean writingAttribute) { |
| this.writingAttribute = writingAttribute; |
| } |
| |
| public Writer escaped() { |
| return this.escapedWriter; |
| } |
| |
| public Writer unescaped() { |
| return this; |
| } |
| |
| public String getEncoding() { |
| return this.encoding; |
| } |
| } |