Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Loth2017-02-28 01:04:14 -0500
committerSarika Sinha2017-02-28 23:21:34 -0500
commitb880d44d7e2ff505bfed40ca37b130b24e60993d (patch)
tree65a0b01f8dae9a06228135ac78a77cae771b60b9
parent3014f2fdbe89cfb3ab8923d73fc8702ed0fcb4cb (diff)
downloadeclipse.platform.debug-I20170301-2000.tar.gz
eclipse.platform.debug-I20170301-2000.tar.xz
eclipse.platform.debug-I20170301-2000.zip
Bug 507664 - IOConsoleOutputStream does not handle multi-byte charactersI20170301-2000
at buffer boundaries correctly Change-Id: Ib1651069ab6a1a09d26e0b33bfae2dc3aef2fd77 Signed-off-by: Andreas Loth <andy_2639@justmail.de>
-rw-r--r--org.eclipse.debug.tests/META-INF/MANIFEST.MF3
-rw-r--r--org.eclipse.debug.tests/src/org/eclipse/debug/tests/AutomatedSuite.java10
-rw-r--r--org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/ConsoleManagerTests.java52
-rw-r--r--org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/ConsoleTests.java60
-rw-r--r--org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/TestHelper.java49
-rw-r--r--org.eclipse.ui.console/src/org/eclipse/ui/console/IOConsole.java53
-rw-r--r--org.eclipse.ui.console/src/org/eclipse/ui/console/IOConsoleOutputStream.java92
-rw-r--r--org.eclipse.ui.console/src/org/eclipse/ui/console/MessageConsole.java4
-rw-r--r--org.eclipse.ui.console/src/org/eclipse/ui/console/MessageConsoleStream.java45
-rw-r--r--org.eclipse.ui.console/src/org/eclipse/ui/internal/console/StreamDecoder.java96
10 files changed, 374 insertions, 90 deletions
diff --git a/org.eclipse.debug.tests/META-INF/MANIFEST.MF b/org.eclipse.debug.tests/META-INF/MANIFEST.MF
index 5f2db82d6..81028df52 100644
--- a/org.eclipse.debug.tests/META-INF/MANIFEST.MF
+++ b/org.eclipse.debug.tests/META-INF/MANIFEST.MF
@@ -14,7 +14,8 @@ Require-Bundle: org.eclipse.ui;bundle-version="[3.6.0,4.0.0)",
org.eclipse.core.resources;bundle-version="[3.5.0,4.0.0)",
org.eclipse.debug.core;bundle-version="[3.9.0,4.0.0)",
org.eclipse.ui.externaltools;bundle-version="[3.3.0,4.0.0)",
- org.eclipse.ui.console;bundle-version="[3.7.0,4.0.0)"
+ org.eclipse.ui.console;bundle-version="[3.7.0,4.0.0)",
+ org.eclipse.text
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-Vendor: %providerName
diff --git a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/AutomatedSuite.java b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/AutomatedSuite.java
index 2204d97f1..5c3e1f70c 100644
--- a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/AutomatedSuite.java
+++ b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/AutomatedSuite.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2014 IBM Corporation and others.
+ * Copyright (c) 2009, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -12,11 +12,9 @@
*******************************************************************************/
package org.eclipse.debug.tests;
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
import org.eclipse.debug.tests.breakpoint.BreakpointOrderingTests;
import org.eclipse.debug.tests.console.ConsoleManagerTests;
+import org.eclipse.debug.tests.console.ConsoleTests;
import org.eclipse.debug.tests.launching.AcceleratorSubstitutionTests;
import org.eclipse.debug.tests.launching.ArgumentParsingTests;
import org.eclipse.debug.tests.launching.LaunchConfigurationTests;
@@ -41,6 +39,9 @@ import org.eclipse.debug.tests.viewer.model.VirtualViewerSelectionTests;
import org.eclipse.debug.tests.viewer.model.VirtualViewerStateTests;
import org.eclipse.debug.tests.viewer.model.VirtualViewerUpdateTests;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
/**
* Tests for integration and nightly builds.
*
@@ -104,6 +105,7 @@ public class AutomatedSuite extends TestSuite {
// Console view
addTest(new TestSuite(ConsoleManagerTests.class));
+ addTest(new TestSuite(ConsoleTests.class));
// Launch Groups
addTest(new TestSuite(LaunchGroupTests.class));
diff --git a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/ConsoleManagerTests.java b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/ConsoleManagerTests.java
index 0e3d7fd4d..fb0a025ec 100644
--- a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/ConsoleManagerTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/ConsoleManagerTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2016 Andrey Loskutov and others.
+ * Copyright (c) 2016, 2017 Andrey Loskutov and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -16,7 +16,6 @@ import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
-import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.swt.SWT;
@@ -61,7 +60,7 @@ public class ConsoleManagerTests extends TestCase {
manager = ConsolePlugin.getDefault().getConsoleManager();
IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
hideWelcomePage(activePage);
- processUIEvents(100);
+ TestHelper.processUIEvents(100);
consoles = new ConsoleMock[count];
for (int i = 0; i < count; i++) {
final ConsoleMock console = new ConsoleMock(i + 1);
@@ -72,7 +71,7 @@ public class ConsoleManagerTests extends TestCase {
IViewPart consoleView = activePage.showView("org.eclipse.ui.console.ConsoleView"); //$NON-NLS-1$
activePage.activate(consoleView);
- processUIEvents(100);
+ TestHelper.processUIEvents(100);
// The test is unstable ("show" event on the the first console seem to
// be not always sent), so make sure console view has shown at least
@@ -80,8 +79,8 @@ public class ConsoleManagerTests extends TestCase {
firstConsole = new ConsoleMock(0);
manager.addConsoles(new ConsoleMock[] { firstConsole });
manager.showConsoleView(firstConsole);
- waitForJobs();
- processUIEvents(100);
+ TestHelper.waitForJobs();
+ TestHelper.processUIEvents(100);
ConsoleMock.allShownConsoles.set(0);
}
@@ -90,7 +89,7 @@ public class ConsoleManagerTests extends TestCase {
executorService.shutdownNow();
manager.removeConsoles(consoles);
manager.removeConsoles(new ConsoleMock[] { firstConsole });
- processUIEvents(100);
+ TestHelper.processUIEvents(100);
super.tearDown();
}
@@ -104,7 +103,7 @@ public class ConsoleManagerTests extends TestCase {
}
if (intro != null) {
activePage.hideView(intro);
- processUIEvents(100);
+ TestHelper.processUIEvents(100);
}
}
@@ -124,15 +123,15 @@ public class ConsoleManagerTests extends TestCase {
showConsole(console);
}
System.out.println("All tasks scheduled, processing UI events now..."); //$NON-NLS-1$
- processUIEvents(1000);
+ TestHelper.processUIEvents(1000);
// Console manager starts a job with delay, let wait for him a bit
System.out.println("Waiting on jobs now..."); //$NON-NLS-1$
- waitForJobs();
+ TestHelper.waitForJobs();
// Give UI a chance to proceed pending console manager jobs
System.out.println("Done with jobs, processing UI events again..."); //$NON-NLS-1$
- processUIEvents(3000);
+ TestHelper.processUIEvents(3000);
executorService.shutdown();
@@ -140,7 +139,7 @@ public class ConsoleManagerTests extends TestCase {
boolean OK = waitForExecutorService();
if (!OK) {
System.out.println("Timed out..."); //$NON-NLS-1$
- processUIEvents(10000);
+ TestHelper.processUIEvents(10000);
// timeout?
assertTrue("Timeout occurred while waiting on console to be shown", //$NON-NLS-1$
@@ -157,35 +156,11 @@ public class ConsoleManagerTests extends TestCase {
if (executorService.awaitTermination(1, TimeUnit.SECONDS)) {
return true;
}
- processUIEvents(100);
+ TestHelper.processUIEvents(100);
}
return false;
}
- private void processUIEvents(final long millis) {
- long start = System.currentTimeMillis();
- while (System.currentTimeMillis() - start < millis) {
- while (PlatformUI.getWorkbench().getDisplay().readAndDispatch()) {
- // loop untile the queue is empty
- }
- }
- }
-
- private void waitForJobs() throws InterruptedException {
- if (Display.getCurrent() == null) {
- Thread.sleep(200);
- } else {
- processUIEvents(200);
- }
- while (!Job.getJobManager().isIdle()) {
- if (Display.getCurrent() == null) {
- Thread.sleep(200);
- } else {
- processUIEvents(200);
- }
- }
- }
-
private void showConsole(final ConsoleMock console) {
executorService.execute(new Runnable() {
@Override
@@ -197,7 +172,7 @@ public class ConsoleManagerTests extends TestCase {
latch.await(1, TimeUnit.MINUTES);
System.out.println("Requesting to show: " + console); //$NON-NLS-1$
manager.showConsoleView(console);
- waitForJobs();
+ TestHelper.waitForJobs();
} catch (InterruptedException e) {
e.printStackTrace();
Thread.interrupted();
@@ -277,4 +252,5 @@ public class ConsoleManagerTests extends TestCase {
return "mock #" + number; //$NON-NLS-1$
}
}
+
}
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
new file mode 100644
index 000000000..3939c4d3a
--- /dev/null
+++ b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/ConsoleTests.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Andreas Loth and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andreas Loth - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.debug.tests.console;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.ui.console.IConsoleConstants;
+import org.eclipse.ui.console.IOConsoleOutputStream;
+import org.eclipse.ui.console.MessageConsole;
+
+import junit.framework.TestCase;
+
+
+public class ConsoleTests extends TestCase {
+
+ public ConsoleTests() {
+ super("ConsoleTests"); //$NON-NLS-1$
+ }
+
+ public ConsoleTests(String name) {
+ super(name);
+ }
+
+ public void testConsoleOutputStreamEncoding() throws IOException, InterruptedException {
+ String testString = "abc\u00e4\u00f6\u00fcdef"; //$NON-NLS-1$
+ // abcdef need 1 byte in UTF-8 each
+ // äöü (\u00e4\u00f6\u00fc) need 2 bytes each
+ byte[] testStringBuffer = testString.getBytes(StandardCharsets.UTF_8);
+ TestCase.assertEquals("Test string \"" + testString + "\" should consist of 12 UTF-8 bytes", 12, testStringBuffer.length); //$NON-NLS-1$ //$NON-NLS-2$
+ MessageConsole console = new MessageConsole("Test Console", //$NON-NLS-1$
+ IConsoleConstants.MESSAGE_CONSOLE_TYPE, null, StandardCharsets.UTF_8.name(), true);
+ IDocument document = console.getDocument();
+ TestHelper.waitForJobs();
+ TestCase.assertEquals("Document should be empty", "", document.get()); //$NON-NLS-1$ //$NON-NLS-2$
+ try (IOConsoleOutputStream outStream = console.newOutputStream()) {
+ outStream.write(testStringBuffer, 0, 6);
+ // half of ö (\u00f6) is written so we don't expect this char in
+ // output but all previous chars can be decoded
+ TestHelper.waitForJobs();
+ TestCase.assertEquals("First 4 chars should be written", testString.substring(0, 4), document.get()); //$NON-NLS-1$
+ outStream.write(testStringBuffer, 6, 6);
+ // all remaining bytes are written so we expect the whole string
+ // including the ö (\u00f6) which was at buffer boundary
+ TestHelper.waitForJobs();
+ TestCase.assertEquals("whole test string should be written", testString, document.get()); //$NON-NLS-1$
+ }
+ }
+
+}
diff --git a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/TestHelper.java b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/TestHelper.java
new file mode 100644
index 000000000..981459a79
--- /dev/null
+++ b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/TestHelper.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Andreas Loth and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andreas Loth - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.debug.tests.console;
+
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.PlatformUI;
+
+
+public final class TestHelper {
+
+ private TestHelper() {
+ throw new AssertionError("No instances of this utility class!"); //$NON-NLS-1$
+ }
+
+ public static void processUIEvents(final long millis) {
+ long start = System.currentTimeMillis();
+ while (System.currentTimeMillis() - start < millis) {
+ while (PlatformUI.getWorkbench().getDisplay().readAndDispatch()) {
+ // loop untile the queue is empty
+ }
+ }
+ }
+
+ public static void waitForJobs() throws InterruptedException {
+ if (Display.getCurrent() == null) {
+ Thread.sleep(200);
+ } else {
+ processUIEvents(200);
+ }
+ while (!Job.getJobManager().isIdle()) {
+ if (Display.getCurrent() == null) {
+ Thread.sleep(200);
+ } else {
+ processUIEvents(200);
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.ui.console/src/org/eclipse/ui/console/IOConsole.java b/org.eclipse.ui.console/src/org/eclipse/ui/console/IOConsole.java
index 1f573f70f..44cbfc4d7 100644
--- a/org.eclipse.ui.console/src/org/eclipse/ui/console/IOConsole.java
+++ b/org.eclipse.ui.console/src/org/eclipse/ui/console/IOConsole.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -15,12 +15,12 @@ package org.eclipse.ui.console;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
+import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.jface.resource.ImageDescriptor;
-
import org.eclipse.ui.WorkbenchEncoding;
import org.eclipse.ui.internal.console.IOConsolePage;
import org.eclipse.ui.internal.console.IOConsolePartitioner;
@@ -54,7 +54,7 @@ public class IOConsole extends TextConsole {
/**
* The encoding used to for displaying console output.
*/
- private String fEncoding = WorkbenchEncoding.getWorkbenchDefaultEncoding();
+ private Charset charset;
/**
@@ -68,7 +68,7 @@ public class IOConsole extends TextConsole {
* when this console is added/removed from the console manager
*/
public IOConsole(String name, String consoleType, ImageDescriptor imageDescriptor, boolean autoLifecycle) {
- this(name, consoleType, imageDescriptor, null, autoLifecycle);
+ this(name, consoleType, imageDescriptor, (String)null, autoLifecycle);
}
/**
@@ -83,10 +83,31 @@ public class IOConsole extends TextConsole {
* when this console is added/removed from the console manager
*/
public IOConsole(String name, String consoleType, ImageDescriptor imageDescriptor, String encoding, boolean autoLifecycle) {
+ this(name, consoleType, imageDescriptor,
+ encoding == null
+ ? Charset.forName(WorkbenchEncoding.getWorkbenchDefaultEncoding())
+ : Charset.forName(encoding),
+ autoLifecycle);
+ }
+
+ /**
+ * Constructs a console with the given name, type, image, encoding and
+ * lifecycle.
+ *
+ * @param name name to display for this console
+ * @param consoleType console type identifier or <code>null</code>
+ * @param imageDescriptor image to display for this console or
+ * <code>null</code>
+ * @param charset the encoding that should be used to render the text, must
+ * not be <code>null</code>
+ * @param autoLifecycle whether lifecycle methods should be called
+ * automatically when this console is added/removed from the
+ * console manager
+ * @since 3.7
+ */
+ public IOConsole(String name, String consoleType, ImageDescriptor imageDescriptor, Charset charset, boolean autoLifecycle) {
super(name, consoleType, imageDescriptor, autoLifecycle);
- if (encoding != null) {
- fEncoding = encoding;
- }
+ this.charset = charset;
synchronized (openStreams) {
inputStream = new IOConsoleInputStream(this);
openStreams.add(inputStream);
@@ -144,8 +165,7 @@ public class IOConsole extends TextConsole {
* @return a new output stream connected to this console
*/
public IOConsoleOutputStream newOutputStream() {
- IOConsoleOutputStream outputStream = new IOConsoleOutputStream(this);
- outputStream.setEncoding(fEncoding);
+ IOConsoleOutputStream outputStream = new IOConsoleOutputStream(this, this.charset);
synchronized(openStreams) {
openStreams.add(outputStream);
}
@@ -301,6 +321,19 @@ public class IOConsole extends TextConsole {
* @since 3.3
*/
public String getEncoding() {
- return fEncoding;
+ return this.charset.name();
}
+
+ /**
+ * Returns the Charset for this console, or <code>null</code> to indicate
+ * default encoding.
+ *
+ * @return the Charset for this console, or <code>null</code> to indicate
+ * default encoding
+ * @since 3.7
+ */
+ public Charset getCharset() {
+ return this.charset;
+ }
+
}
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 08efd3bfd..7e78ddf6a 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
@@ -13,10 +13,11 @@ package org.eclipse.ui.console;
import java.io.IOException;
import java.io.OutputStream;
+import java.nio.charset.Charset;
import org.eclipse.swt.graphics.Color;
-import org.eclipse.ui.WorkbenchEncoding;
import org.eclipse.ui.internal.console.IOConsolePartitioner;
+import org.eclipse.ui.internal.console.StreamDecoder;
/**
* OutputStream used to write to an IOConsole.
@@ -66,10 +67,7 @@ public class IOConsoleOutputStream extends OutputStream {
*/
private int fontStyle;
- private String fEncoding;
- private String fDefaultEncoding = WorkbenchEncoding.getWorkbenchDefaultEncoding();
-
- private boolean fNeedsEncoding = false;
+ private StreamDecoder decoder;
private boolean prependCR;
@@ -78,8 +76,9 @@ public class IOConsoleOutputStream extends OutputStream {
*
* @param console I/O console
*/
- IOConsoleOutputStream(IOConsole console) {
- this.console = console;
+ IOConsoleOutputStream(IOConsole console, Charset charset) {
+ this.decoder = new StreamDecoder(charset);
+ this.console = console;
this.partitioner = (IOConsolePartitioner) console.getPartitioner();
}
@@ -195,11 +194,9 @@ public class IOConsoleOutputStream extends OutputStream {
*/
@Override
public void write(byte[] b, int off, int len) throws IOException {
- if (fNeedsEncoding) {
- encodedWrite(new String(b, off, len, fEncoding));
- } else {
- encodedWrite(new String(b, off, len));
- }
+ StringBuilder builder = new StringBuilder();
+ this.decoder.decode(builder, b, off, len);
+ encodedWrite(builder.toString());
}
/*
* (non-Javadoc)
@@ -218,12 +215,51 @@ public class IOConsoleOutputStream extends OutputStream {
write(new byte[] {(byte)b}, 0, 1);
}
+ /**
+ * Writes a character array to the attached console.
+ *
+ * @param buffer the char array to write to the attached console
+ * @throws IOException if the stream is closed
+ * @since 3.7
+ */
+ public void write(char[] buffer) throws IOException {
+ String str = new String(buffer);
+ this.encodedWrite(str);
+ }
+
+ /**
+ * Writes a character array using specified offset and length to the
+ * attached console.
+ *
+ * @param buffer the char array to write to the attached console.
+ * @param off the initial offset
+ * @param len the length
+ * @throws IOException if the stream is closed
+ * @since 3.7
+ */
+ public void write(char[] buffer, int off, int len) throws IOException {
+ String str = new String(buffer, off, len);
+ this.encodedWrite(str);
+ }
+
/**
- * Writes a string to the attached console.
- *
- * @param str the string to write to the attached console.
- * @throws IOException if the stream is closed.
- */
+ * Writes a character sequence to the attached console.
+ *
+ * @param chars the string/characters to write to the attached console.
+ * @throws IOException if the stream is closed.
+ * @since 3.7
+ */
+ public void write(CharSequence chars) throws IOException {
+ String str = chars.toString();
+ encodedWrite(str);
+ }
+
+ /**
+ * Writes a string to the attached console.
+ *
+ * @param str the string to write to the attached console
+ * @throws IOException if the stream is closed
+ */
public void write(String str) throws IOException {
encodedWrite(str);
}
@@ -267,7 +303,25 @@ public class IOConsoleOutputStream extends OutputStream {
* @param encoding encoding identifier
*/
public void setEncoding(String encoding) {
- fEncoding = encoding;
- fNeedsEncoding = (fEncoding!=null) && (!fEncoding.equals(fDefaultEncoding));
+ Charset charset = Charset.forName(encoding);
+ try {
+ this.setCharset(charset);
+ } catch (IOException ioe) {
+ // ignore exception while writing final characters
+ // to avoid API break
+ }
+ }
+
+ /**
+ * @param charset set the Charset for the attached console
+ * @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());
+ this.decoder = new StreamDecoder(charset);
}
+
}
diff --git a/org.eclipse.ui.console/src/org/eclipse/ui/console/MessageConsole.java b/org.eclipse.ui.console/src/org/eclipse/ui/console/MessageConsole.java
index d7ea0d0f2..aa399164e 100644
--- a/org.eclipse.ui.console/src/org/eclipse/ui/console/MessageConsole.java
+++ b/org.eclipse.ui.console/src/org/eclipse/ui/console/MessageConsole.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -124,7 +124,7 @@ public class MessageConsole extends IOConsole {
* @return a new message stream connected to this console
*/
public MessageConsoleStream newMessageStream() {
- return new MessageConsoleStream(this);
+ return new MessageConsoleStream(this, this.getCharset());
}
/* (non-Javadoc)
diff --git a/org.eclipse.ui.console/src/org/eclipse/ui/console/MessageConsoleStream.java b/org.eclipse.ui.console/src/org/eclipse/ui/console/MessageConsoleStream.java
index 274e8a8f2..c8593d53a 100644
--- a/org.eclipse.ui.console/src/org/eclipse/ui/console/MessageConsoleStream.java
+++ b/org.eclipse.ui.console/src/org/eclipse/ui/console/MessageConsoleStream.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2008 IBM Corporation and others.
+ * Copyright (c) 2000, 20017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -11,6 +11,9 @@
package org.eclipse.ui.console;
import java.io.IOException;
+import java.nio.charset.Charset;
+
+import org.eclipse.ui.WorkbenchEncoding;
/**
* Used to write messages to a message console. A message console may have more
@@ -33,22 +36,32 @@ import java.io.IOException;
* @noextend This class is not intended to be subclassed by clients.
*/
public class MessageConsoleStream extends IOConsoleOutputStream {
-
+
private MessageConsole fMessageConsole;
-
+
/**
* Constructs a new stream connected to the given console.
- *
+ *
* @param console the console to write messages to
*/
public MessageConsoleStream(MessageConsole console) {
- super(console);
+ this(console, Charset.forName(WorkbenchEncoding.getWorkbenchDefaultEncoding()));
+ }
+
+ /**
+ * Constructs a new stream connected to the given console.
+ *
+ * @param console the console to write messages to
+ * @since 3.7
+ */
+ public MessageConsoleStream(MessageConsole console, Charset charset) {
+ super(console, charset);
fMessageConsole = console;
}
-
+
/**
* Appends the specified message to this stream.
- *
+ *
* @param message message to append
*/
public void print(String message) {
@@ -58,8 +71,8 @@ public class MessageConsoleStream extends IOConsoleOutputStream {
ConsolePlugin.log(e);
}
}
-
-
+
+
/**
* Appends a line separator string to this stream.
*/
@@ -69,24 +82,24 @@ public class MessageConsoleStream extends IOConsoleOutputStream {
} catch (IOException e) {
ConsolePlugin.log(e);
}
- }
-
+ }
+
/**
* Appends the specified message to this stream, followed by a line
* separator string.
- *
+ *
* @param message message to print
*/
public void println(String message) {
print(message + "\n"); //$NON-NLS-1$
- }
-
+ }
+
/**
* Returns the console this stream is connected to.
- *
+ *
* @return the console this stream is connected to
*/
public MessageConsole getConsole() {
return fMessageConsole;
- }
+ }
}
diff --git a/org.eclipse.ui.console/src/org/eclipse/ui/internal/console/StreamDecoder.java b/org.eclipse.ui.console/src/org/eclipse/ui/internal/console/StreamDecoder.java
new file mode 100644
index 000000000..dde14fdcd
--- /dev/null
+++ b/org.eclipse.ui.console/src/org/eclipse/ui/internal/console/StreamDecoder.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Andreas Loth and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andreas Loth - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.console;
+
+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.nio.charset.CodingErrorAction;
+
+
+/**
+ * @since 3.7
+ */
+public class StreamDecoder {
+
+ static private final int BUFFER_SIZE = 4096;
+
+ private final CharsetDecoder decoder;
+ private final ByteBuffer inputBuffer;
+ private final CharBuffer outputBuffer;
+
+ public StreamDecoder(Charset charset) {
+ this.decoder = charset.newDecoder();
+ this.decoder.onMalformedInput(CodingErrorAction.REPLACE);
+ this.decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
+ this.inputBuffer = ByteBuffer.allocate(StreamDecoder.BUFFER_SIZE);
+ this.inputBuffer.flip();
+ this.outputBuffer = CharBuffer.allocate(StreamDecoder.BUFFER_SIZE);
+ }
+
+ private void consume(StringBuilder consumer) {
+ this.outputBuffer.flip();
+ consumer.append(this.outputBuffer);
+ this.outputBuffer.clear();
+ }
+
+ private void internalDecode(StringBuilder consumer, byte[] buffer, int offset, int length, boolean last) {
+ assert (offset >= 0);
+ assert (length >= 0);
+ int position = offset;
+ int end = offset + length;
+ assert (end <= buffer.length);
+ boolean finished = false;
+ do {
+ CoderResult result = this.decoder.decode(this.inputBuffer, this.outputBuffer, last);
+ if (result.isOverflow()) {
+ this.consume(consumer);
+ } else if (result.isUnderflow()) {
+ this.inputBuffer.compact();
+ int remaining = this.inputBuffer.remaining();
+ assert (remaining > 0);
+ int read = Math.min(remaining, end - position);
+ if (read > 0) {
+ this.inputBuffer.put(buffer, position, read);
+ position += read;
+ } else {
+ finished = true;
+ }
+ this.inputBuffer.flip();
+ } else {
+ assert false;
+ }
+ } while (!finished);
+ }
+
+ public void decode(StringBuilder consumer, byte[] buffer, int offset, int length) {
+ this.internalDecode(consumer, buffer, offset, length, false);
+ this.consume(consumer);
+ }
+
+ public void finish(StringBuilder consumer) {
+ this.internalDecode(consumer, new byte[0], 0, 0, true);
+ CoderResult result;
+ do {
+ result = this.decoder.flush(this.outputBuffer);
+ if (result.isOverflow()) {
+ this.consume(consumer);
+ } else {
+ assert result.isUnderflow();
+ }
+ } while (!result.isUnderflow());
+ this.consume(consumer);
+ }
+
+}

Back to the top