blob: 786194e82b160435daf4f38e79521e7476f66c5f [file] [log] [blame]
/*
* 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("&lt;");
} else if (c == '>') {
StreamingMarkupWriter.this.writer.write("&gt;");
} else if (c == '&') {
StreamingMarkupWriter.this.writer.write("&amp;");
} 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("&apos;");
} 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;
}
}