Mercurial > hg > monetdb-java
diff src/main/java/org/monetdb/mcl/net/MapiSocket.java @ 616:65641a7cea31
Implement line ending conversion for downloads
MonetConnection.Download#getStream returns an InputStream which
converts line endings when in text mode.
The default line ending is the platform line ending but that can be
changed. Setting it to \n can be a useful optimization if you don't
need the \r's anyway.
author | Joeri van Ruth <joeri.van.ruth@monetdbsolutions.com> |
---|---|
date | Wed, 19 Jan 2022 14:58:01 +0100 (2022-01-19) |
parents | 1d44b8a577ca |
children | 06d69b82d409 |
line wrap: on
line diff
--- a/src/main/java/org/monetdb/mcl/net/MapiSocket.java +++ b/src/main/java/org/monetdb/mcl/net/MapiSocket.java @@ -1198,9 +1198,10 @@ public class MapiSocket { /* cannot (yet * Return a DownloadStream for use with for example COPY INTO filename ON CLIENT * * Building block for {@link org.monetdb.jdbc.MonetConnection.DownloadHandler}. + * @param prependCr convert \n to \r\n */ - public DownloadStream downloadStream() { - return new DownloadStream(fromMonet.getRaw(), toMonet); + public DownloadStream downloadStream(boolean prependCr) { + return new DownloadStream(fromMonet.getRaw(), toMonet, prependCr); } /** @@ -1379,12 +1380,15 @@ public class MapiSocket { /* cannot (yet public static class DownloadStream extends InputStream { private final BlockInputStream.Raw rawIn; private final OutputStream out; + private final boolean prependCr; private boolean endBlockSeen = false; private boolean closed = false; + private boolean newlinePending = false; // used for crlf conversion - DownloadStream(BlockInputStream.Raw rawIn, OutputStream out) { + DownloadStream(BlockInputStream.Raw rawIn, OutputStream out, boolean prependCr) { this.rawIn = rawIn; this.out = out; + this.prependCr = prependCr; } void nextBlock() throws IOException { @@ -1422,23 +1426,55 @@ public class MapiSocket { /* cannot (yet } @Override - public int read(final byte[] b, int off, int len) throws IOException { + public int read(final byte[] dest, int off, int len) throws IOException { final int origOff = off; - while (len > 0) { - int chunk = Integer.min(len, rawIn.getLength() - rawIn.getPosition()); - if (chunk > 0) { - // make progress copying some bytes - System.arraycopy(rawIn.getBytes(), rawIn.getPosition(), b, off, chunk); - off += chunk; - rawIn.consume(chunk); - len -= chunk; - } else { - // make progress fetching data + int end = off + len; + + while (off < end) { + // minimum of what's requested and what we have in stock + int chunk = Integer.min(end - off, rawIn.getLength() - rawIn.getPosition()); + assert chunk >= 0; + if (chunk == 0) { + // make progress by fetching more data if (endBlockSeen) break; nextBlock(); + continue; + } + // make progress copying some bytes + if (!prependCr) { + // no conversion needed, use arraycopy + System.arraycopy(rawIn.getBytes(), rawIn.getPosition(), dest, off, chunk); + off += chunk; + rawIn.consume(chunk); + } else { + int chunkEnd = off + chunk; + if (newlinePending && off < chunkEnd) { + // we were in the middle of a line ending conversion + dest[off++] = '\n'; + newlinePending = false; + } + while (off < chunkEnd) { + byte b = rawIn.getBytes()[rawIn.consume(1)]; + if (b != '\n') { + dest[off++] = b; + } else if (chunkEnd - off >= 2) { + dest[off++] = '\r'; + dest[off++] = '\n'; + } else { + dest[off++] = '\r'; + newlinePending = true; + break; + } + } } } + + if (off < end && newlinePending) { + dest[off++] = '\n'; + newlinePending = false; + } + if (off == origOff && endBlockSeen) return -1; else