/*******************************************************************************
*
* Copyright (c) 2004-2009 Oracle Corporation.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*
* Kohsuke Kawaguchi
*
*
*******************************************************************************/
package hudson.util;
import java.io.OutputStream;
import java.io.Writer;
import java.io.IOException;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.CoderResult;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.nio.*;
/**
* {@link OutputStream} that writes to {@link Writer} by assuming the platform
* default encoding.
*
* @author Kohsuke Kawaguchi
* @deprecated since 2008-05-28. Use the one in stapler.
*/
public class WriterOutputStream extends OutputStream {
private final Writer writer;
private final CharsetDecoder decoder;
private java.nio.ByteBuffer buf = java.nio.ByteBuffer.allocate(1024);
private CharBuffer out = CharBuffer.allocate(1024);
public WriterOutputStream(Writer out) {
this.writer = out;
decoder = DEFAULT_CHARSET.newDecoder();
decoder.onMalformedInput(CodingErrorAction.REPLACE);
decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
}
public void write(int b) throws IOException {
if (buf.remaining() == 0) {
decode(false);
}
buf.put((byte) b);
}
public void write(byte b[], int off, int len) throws IOException {
while (len > 0) {
if (buf.remaining() == 0) {
decode(false);
}
int sz = Math.min(buf.remaining(), len);
buf.put(b, off, sz);
off += sz;
len -= sz;
}
}
public void flush() throws IOException {
decode(false);
flushOutput();
writer.flush();
}
private void flushOutput() throws IOException {
writer.write(out.array(), 0, out.position());
out.clear();
}
public void close() throws IOException {
decode(true);
flushOutput();
writer.close();
buf.rewind();
}
/**
* Decodes the contents of {@link #buf} as much as possible to {@link #out}.
* If necessary {@link #out} is further sent to {@link #writer}.
*
* <p> When this method returns, the {@link #buf} is back to the
* 'accumulation' mode.
*
* @param last if true, tell the decoder that all the input bytes are ready.
*/
private void decode(boolean last) throws IOException {
buf.flip();
while (true) {
CoderResult r = decoder.decode(buf, out, last);
if (r == CoderResult.OVERFLOW) {
flushOutput();
continue;
}
if (r == CoderResult.UNDERFLOW) {
buf.compact();
return;
}
// otherwise treat it as an error
r.throwException();
}
}
private static final Charset DEFAULT_CHARSET = getDefaultCharset();
private static Charset getDefaultCharset() {
try {
String encoding = System.getProperty("file.encoding");
return Charset.forName(encoding);
} catch (UnsupportedCharsetException e) {
return Charset.forName("UTF-8");
}
}
}