|
@@ -7,13 +7,18 @@
|
|
|
|
|
|
|
|
package net.ranides.assira.io;
|
|
package net.ranides.assira.io;
|
|
|
|
|
|
|
|
-import java.io.ByteArrayOutputStream;
|
|
|
|
|
import java.io.FilterInputStream;
|
|
import java.io.FilterInputStream;
|
|
|
import java.io.FilterOutputStream;
|
|
import java.io.FilterOutputStream;
|
|
|
import java.io.IOException;
|
|
import java.io.IOException;
|
|
|
import java.io.InputStream;
|
|
import java.io.InputStream;
|
|
|
import java.io.OutputStream;
|
|
import java.io.OutputStream;
|
|
|
import java.io.PrintStream;
|
|
import java.io.PrintStream;
|
|
|
|
|
+import java.io.Writer;
|
|
|
|
|
+import java.nio.ByteBuffer;
|
|
|
|
|
+import java.nio.CharBuffer;
|
|
|
|
|
+import java.nio.charset.Charset;
|
|
|
|
|
+import java.nio.charset.CharsetDecoder;
|
|
|
|
|
+import java.nio.charset.CoderResult;
|
|
|
import java.util.Arrays;
|
|
import java.util.Arrays;
|
|
|
import java.util.function.Consumer;
|
|
import java.util.function.Consumer;
|
|
|
import net.ranides.assira.events.EventListener;
|
|
import net.ranides.assira.events.EventListener;
|
|
@@ -95,6 +100,10 @@ public final class IOStreams {
|
|
|
return tee(new StringOutput());
|
|
return tee(new StringOutput());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ public static OutputStream stream(Writer writer, Charset cs) {
|
|
|
|
|
+ return new WriterStream(writer, cs);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private static final class InputObserver extends FilterInputStream {
|
|
private static final class InputObserver extends FilterInputStream {
|
|
|
|
|
|
|
|
private final EventListener<? super IOEvent> listener;
|
|
private final EventListener<? super IOEvent> listener;
|
|
@@ -319,5 +328,83 @@ public final class IOStreams {
|
|
|
void run(OutputStream os) throws IOException;
|
|
void run(OutputStream os) throws IOException;
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ private static final class WriterStream extends OutputStream {
|
|
|
|
|
+
|
|
|
|
|
+ private final CharsetDecoder cd;
|
|
|
|
|
+ private final Writer writer;
|
|
|
|
|
+ private final ByteBuffer buffer;
|
|
|
|
|
+
|
|
|
|
|
+ public WriterStream(Writer writer, Charset cs) {
|
|
|
|
|
+ this.cd = cs.newDecoder();
|
|
|
|
|
+ this.writer = writer;
|
|
|
|
|
+ this.buffer = ByteBuffer.allocate(128);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void write(int b) throws IOException {
|
|
|
|
|
+ buffer.put((byte)b);
|
|
|
|
|
+ if(buffer.remaining()==0) {
|
|
|
|
|
+ flush();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void write(byte[] b, int off, int len) throws IOException {
|
|
|
|
|
+ if(buffer.remaining() < len) {
|
|
|
|
|
+ flush();
|
|
|
|
|
+ write(ByteBuffer.wrap(b, off, len), false);
|
|
|
|
|
+ }
|
|
|
|
|
+ buffer.put(b, off, len);
|
|
|
|
|
+ if(buffer.remaining()==0) {
|
|
|
|
|
+ flush();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void flush() throws IOException {
|
|
|
|
|
+ buffer.flip();
|
|
|
|
|
+ write(buffer, false);
|
|
|
|
|
+ writer.flush();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void close() throws IOException {
|
|
|
|
|
+ buffer.flip();
|
|
|
|
|
+ write(buffer, true);
|
|
|
|
|
+ writer.flush();
|
|
|
|
|
+ writer.close();
|
|
|
|
|
+ super.close();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void write(ByteBuffer src, boolean end) throws IOException {
|
|
|
|
|
+ if (0 == src.remaining()) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ int n = (int)(src.remaining() * cd.averageCharsPerByte());
|
|
|
|
|
+ CharBuffer out = CharBuffer.allocate(n);
|
|
|
|
|
+
|
|
|
|
|
+ while(true) {
|
|
|
|
|
+ CoderResult cr = src.hasRemaining() ?
|
|
|
|
|
+ cd.decode(src, out, true) : CoderResult.UNDERFLOW;
|
|
|
|
|
+ if (end && cr.isUnderflow()) {
|
|
|
|
|
+ cr = cd.flush(out);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (cr.isUnderflow()) {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (cr.isOverflow()) {
|
|
|
|
|
+ writer.write(out.array(), 0, out.position());
|
|
|
|
|
+ out.clear();
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ cr.throwException();
|
|
|
|
|
+ }
|
|
|
|
|
+ src.clear();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
}
|
|
}
|