5 import java.nio.channels.*;
6 import java.nio.charset.*;
8 public abstract class LazyPChannel implements ReadableByteChannel {
9 private ByteBuffer curbuf = null;
10 private boolean eof = false;
11 private CharsetEncoder enc = null;
12 private Runnable rem = null;
14 protected boolean write(byte[] data, int off, int len) {
15 if(rem != null) throw(new IllegalStateException("buffer filled"));
16 int t = Math.min(curbuf.remaining(), len);
17 curbuf.put(data, off, t);
19 rem = () -> write(data, off + t, len - t);
24 protected boolean write(byte[] data) {return(write(data, 0, data.length));}
26 protected boolean write(CharBuffer buf) {
27 if(rem != null) throw(new IllegalStateException("buffer filled"));
29 enc = charset().newEncoder();
31 int pp = buf.position();
32 CoderResult res = enc.encode(buf, curbuf, false);
33 if(buf.remaining() == 0)
35 if(res.isUnderflow()) {
36 if(pp == buf.position()) {
37 /* XXX? Not sure if this can be expected to
38 * happen. I'm not aware of any charsets that should
39 * require it, and it would complicate the design
41 throw(new RuntimeException("encoder not consuming input"));
43 } else if(res.isOverflow()) {
44 rem = () -> write(buf);
49 } catch(CharacterCodingException e) {
50 throw(new RuntimeException(e));
56 protected boolean write(CharSequence chars) {
57 CharBuffer buf = (chars instanceof CharBuffer) ? ((CharBuffer)chars).duplicate() : CharBuffer.wrap(chars);
61 private void encflush2() {
63 CoderResult res = enc.flush(curbuf);
64 if(res.isOverflow()) {
65 rem = this::encflush1;
67 } else if(res.isUnderflow()) {
72 } catch(CharacterCodingException e) {
73 throw(new RuntimeException(e));
79 private void encflush1() {
80 CharBuffer empty = CharBuffer.wrap("");
82 CoderResult res = enc.encode(empty, curbuf, true);
83 if(res.isOverflow()) {
84 rem = this::encflush1;
86 } else if(res.isUnderflow()) {
87 rem = this::encflush2;
92 } catch(CharacterCodingException e) {
93 throw(new RuntimeException(e));
99 private void encflush() {
101 rem = this::encflush1;
104 protected Charset charset() {return(Http.UTF8);}
106 protected abstract boolean produce();
108 public int read(ByteBuffer buf) {
111 int op = buf.position();
112 while(buf.remaining() > 0) {
113 Runnable rem = this.rem;
120 } else if(produce()) {
126 if(eof && (buf.position() == op))
128 return(buf.position() - op);
134 public void close() {}
135 public boolean isOpen() {return(true);}