Bug 507664 - IOConsoleOutputStream does not handle multi-byte characters
at buffer boundaries correctly

Change-Id: Idfeabbcff7330541c5908ac4b3464a5cce1398ce
Signed-off-by:  Andreas Loth <andy_2639@justmail.de>
diff --git a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/ConsoleTests.java b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/ConsoleTests.java
index 3939c4d..f53a2a3 100644
--- a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/ConsoleTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/ConsoleTests.java
@@ -55,6 +55,9 @@
 			TestHelper.waitForJobs();
 			TestCase.assertEquals("whole test string should be written", testString, document.get()); //$NON-NLS-1$
 		}
+		// after closing the stream, the document content should still be the
+		// same
+		TestCase.assertEquals("closing the stream should not alter the document", testString, document.get()); //$NON-NLS-1$
 	}
 
 }
diff --git a/org.eclipse.ui.console/src/org/eclipse/ui/console/IOConsoleOutputStream.java b/org.eclipse.ui.console/src/org/eclipse/ui/console/IOConsoleOutputStream.java
index 7e78ddf..70291df 100644
--- a/org.eclipse.ui.console/src/org/eclipse/ui/console/IOConsoleOutputStream.java
+++ b/org.eclipse.ui.console/src/org/eclipse/ui/console/IOConsoleOutputStream.java
@@ -14,6 +14,7 @@
 import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
 
 import org.eclipse.swt.graphics.Color;
 import org.eclipse.ui.internal.console.IOConsolePartitioner;
@@ -158,6 +159,20 @@
         return closed;
     }
 
+	/**
+	 * Writes remaining characters stored in the decoder state.
+	 *
+	 * Must only be called from synchronized methods.
+	 *
+	 * @see CharsetDecoder#flush(java.nio.CharBuffer)
+	 * @throws IOException
+	 */
+	private void finishDecoder() throws IOException {
+		StringBuilder builder = new StringBuilder();
+		this.decoder.finish(builder);
+		this.encodedWrite(builder.toString());
+	}
+
 	/*
 	 *  (non-Javadoc)
 	 * @see java.io.OutputStream#close()
@@ -168,6 +183,7 @@
 			// Closeable#close() has no effect if already closed
 			return;
         }
+		this.finishDecoder();
         if (prependCR) { // force writing of last /r
             prependCR = false;
             notifyParitioner("\r"); //$NON-NLS-1$
@@ -193,7 +209,7 @@
      * @see java.io.OutputStream#write(byte[], int, int)
      */
     @Override
-	public void write(byte[] b, int off, int len) throws IOException {
+	public synchronized void write(byte[] b, int off, int len) throws IOException {
 		StringBuilder builder = new StringBuilder();
 		this.decoder.decode(builder, b, off, len);
 		encodedWrite(builder.toString());
@@ -317,10 +333,8 @@
 	 * @throws IOException if the stream is closed
 	 * @since 3.7
 	 */
-	public void setCharset(Charset charset) throws IOException {
-		StringBuilder builder = new StringBuilder();
-		this.decoder.finish(builder);
-		this.encodedWrite(builder.toString());
+	public synchronized void setCharset(Charset charset) throws IOException {
+		this.finishDecoder();
 		this.decoder = new StreamDecoder(charset);
     }