Mercurial > hg > monetdb-java
diff src/main/java/org/monetdb/jdbc/MonetConnection.java @ 613:9397c0b487f8
Normalize CRLF on upload
author | Joeri van Ruth <joeri.van.ruth@monetdbsolutions.com> |
---|---|
date | Tue, 18 Jan 2022 13:18:43 +0100 (2022-01-18) |
parents | 6aa38e8c0f2d |
children | 65641a7cea31 |
line wrap: on
line diff
--- a/src/main/java/org/monetdb/jdbc/MonetConnection.java +++ b/src/main/java/org/monetdb/jdbc/MonetConnection.java @@ -3236,7 +3236,7 @@ public class MonetConnection } final long linesToSkip = offset >= 1 ? offset - 1 : 0; - final Upload handle = new Upload(server, uploadHandler::uploadCancelled); + final Upload handle = new Upload(server, uploadHandler::uploadCancelled, textMode); final boolean wasFaking = server.setInsertFakePrompts(false); try { uploadHandler.handleUpload(handle, path, textMode, linesToSkip); @@ -3326,13 +3326,15 @@ public class MonetConnection public static class Upload { private final MapiSocket server; private final Runnable cancellationCallback; + private final boolean textMode; private PrintStream print = null; private String error = null; private int customChunkSize = -1; - Upload(MapiSocket server, Runnable cancellationCallback) { + Upload(MapiSocket server, Runnable cancellationCallback, boolean textMode) { this.server = server; this.cancellationCallback = cancellationCallback; + this.textMode = textMode; } /** @@ -3374,7 +3376,7 @@ public class MonetConnection try { final MapiSocket.UploadStream up = customChunkSize >= 0 ? server.uploadStream(customChunkSize) : server.uploadStream(); up.setCancellationCallback(cancellationCallback); - print = new PrintStream(up, false, "UTF-8"); + print = new PrintStream(textMode ? new StripCrLfStream(up) : up, false, "UTF-8"); up.write('\n'); } catch (UnsupportedEncodingException e) { throw new RuntimeException("The system is guaranteed to support the UTF-8 encoding but apparently it doesn't", e); @@ -3567,4 +3569,82 @@ public class MonetConnection } } } + + public static class StripCrLfStream extends FilterOutputStream { + private boolean crPending = false; + + public StripCrLfStream(OutputStream out) { + super(out); + } + + public boolean pending() { + return this.crPending; + } + + @Override + public void write(int b) throws IOException { + if (crPending && b != '\n') { + out.write('\r'); + } + if (b != '\r') { + out.write(b); + crPending = false; + } else { + crPending = true; + } + } + + @Override + public void write(byte[] b) throws IOException { + this.write(b, 0, b.length); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + if (len == 0) { + return; + } + if (crPending && b[0] != '\n') { + out.write('\r'); + } + + // deal with final \r up front + if (b[len - 1] == '\r') { + crPending = true; + len -= 1; + } else { + crPending = false; + } + + for (int i = off; i < off + len - 1; i++) { + if (b[i] == '\r' && b[i + 1] == '\n') { + int chunk = i - off; + out.write(b, off, chunk); + // chunk + 1 because we want to skip the \r + len -= chunk + 1; + off += chunk + 1; + // we don't have to look at the \n because we know it's no \r. + i++; + } + } + + // write the remainder + out.write(b, off, len); + } + + @Override + public void flush() throws IOException { + // we cannot flush our pending CR but we can ask our downstream to flush what we have sent them so far + out.flush(); + } + + @Override + public void close() throws IOException { + if (crPending) { + out.write('\r'); + } + crPending = false; + super.close(); + } + } }