Skip to content

Commit 8283aaf

Browse files
committed
Fix possible encoding issues in the new AnsiNoSyncOutputStream
1 parent 182b884 commit 8283aaf

File tree

3 files changed

+80
-7
lines changed

3 files changed

+80
-7
lines changed

jansi/src/main/java/org/fusesource/jansi/AnsiConsole.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ private static PrintStream ansiSystem(boolean stdout) {
127127
// the ansi escapes.
128128
if (getBoolean(JANSI_STRIP)) {
129129
jansiOutputType = JansiOutputType.STRIP_ANSI;
130-
return new PrintStream(new AnsiNoSyncOutputStream(out, new AnsiProcessor(out)), true);
130+
return new PrintStream(new AnsiNoSyncOutputStream(out, new AnsiProcessor(out), enc), true);
131131
}
132132

133133
if (IS_WINDOWS) {
@@ -146,15 +146,15 @@ && SetConsoleMode(console, mode[0] | ENABLE_VIRTUAL_TERMINAL_PROCESSING) != 0) {
146146
// codes but we can use jansi-native Kernel32 API for console
147147
try {
148148
jansiOutputType = JansiOutputType.WINDOWS;
149-
return newPrintStream(new AnsiNoSyncOutputStream(out, new WindowsAnsiProcessor(out, stdout)), enc);
149+
return newPrintStream(new AnsiNoSyncOutputStream(out, new WindowsAnsiProcessor(out, stdout), enc), enc);
150150
} catch (Throwable ignore) {
151151
// this happens when JNA is not in the path.. or
152152
// this happens when the stdout is being redirected to a file.
153153
}
154154

155155
// Use the ANSIOutputStream to strip out the ANSI escape sequences.
156156
jansiOutputType = JansiOutputType.STRIP_ANSI;
157-
return newPrintStream(new AnsiNoSyncOutputStream(out, new AnsiProcessor(out)), enc);
157+
return newPrintStream(new AnsiNoSyncOutputStream(out, new AnsiProcessor(out), enc), enc);
158158
}
159159

160160
// We must be on some Unix variant or ANSI-enabled ConEmu, Cygwin or MSYS(2) on Windows...
@@ -166,7 +166,7 @@ && SetConsoleMode(console, mode[0] | ENABLE_VIRTUAL_TERMINAL_PROCESSING) != 0) {
166166
// to strip the ANSI sequences..
167167
if (!forceColored && isatty(stdout ? 1 : 2) == 0) {
168168
jansiOutputType = JansiOutputType.STRIP_ANSI;
169-
return newPrintStream(new AnsiNoSyncOutputStream(out, new AnsiProcessor(out)), enc);
169+
return newPrintStream(new AnsiNoSyncOutputStream(out, new AnsiProcessor(out), enc), enc);
170170
}
171171
} catch (Throwable ignore) {
172172
// These errors happen if the JNI lib is not available for your platform.

jansi/src/main/java/org/fusesource/jansi/AnsiNoSyncOutputStream.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.io.FilterOutputStream;
1919
import java.io.IOException;
2020
import java.io.OutputStream;
21+
import java.nio.charset.Charset;
2122
import java.util.ArrayList;
2223

2324
/**
@@ -62,10 +63,22 @@ public class AnsiNoSyncOutputStream extends FilterOutputStream {
6263
private int startOfValue;
6364
private final ArrayList<Object> options = new ArrayList<Object>();
6465
private int state = LOOKING_FOR_FIRST_ESC_CHAR;
66+
private final Charset cs;
6567

6668
public AnsiNoSyncOutputStream(OutputStream os, AnsiProcessor ap) {
69+
this(os, ap, Charset.defaultCharset());
70+
}
71+
72+
public AnsiNoSyncOutputStream(OutputStream os, AnsiProcessor ap, Charset cs) {
73+
super(os);
74+
this.ap = ap;
75+
this.cs = cs;
76+
}
77+
78+
public AnsiNoSyncOutputStream(OutputStream os, AnsiProcessor ap, String encoding) {
6779
super(os);
6880
this.ap = ap;
81+
this.cs = encoding != null ? Charset.forName(encoding) : Charset.defaultCharset();
6982
}
7083

7184
/**
@@ -138,7 +151,7 @@ public void write(int data) throws IOException {
138151
case LOOKING_FOR_STR_ARG_END:
139152
buffer[pos++] = (byte) data;
140153
if ('"' != data) {
141-
String value = new String(buffer, startOfValue, (pos - 1) - startOfValue);
154+
String value = new String(buffer, startOfValue, (pos - 1) - startOfValue, cs);
142155
options.add(value);
143156
if (data == ';') {
144157
state = LOOKING_FOR_NEXT_ARG;
@@ -177,7 +190,7 @@ public void write(int data) throws IOException {
177190
case LOOKING_FOR_OSC_PARAM:
178191
buffer[pos++] = (byte) data;
179192
if (BEL == data) {
180-
String value = new String(buffer, startOfValue, (pos - 1) - startOfValue);
193+
String value = new String(buffer, startOfValue, (pos - 1) - startOfValue, cs);
181194
options.add(value);
182195
reset(ap.processOperatingSystemCommand(options));
183196
} else if (FIRST_ESC_CHAR == data) {
@@ -190,7 +203,7 @@ public void write(int data) throws IOException {
190203
case LOOKING_FOR_ST:
191204
buffer[pos++] = (byte) data;
192205
if (SECOND_ST_CHAR == data) {
193-
String value = new String(buffer, startOfValue, (pos - 2) - startOfValue);
206+
String value = new String(buffer, startOfValue, (pos - 2) - startOfValue, cs);
194207
options.add(value);
195208
reset(ap.processOperatingSystemCommand(options));
196209
} else {
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright (C) 2009-2020 the original author(s).
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/package org.fusesource.jansi;
16+
17+
import java.io.ByteArrayOutputStream;
18+
import java.io.PrintStream;
19+
import java.io.UnsupportedEncodingException;
20+
import java.util.concurrent.atomic.AtomicReference;
21+
22+
import org.junit.Test;
23+
24+
import static org.junit.Assert.assertEquals;
25+
26+
public class EncodingTest {
27+
28+
@Test
29+
public void testEncoding8859() throws UnsupportedEncodingException {
30+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
31+
final AtomicReference<String> newLabel = new AtomicReference<String>();
32+
PrintStream ansi = new PrintStream(new AnsiNoSyncOutputStream(baos, new AnsiProcessor(baos) {
33+
@Override
34+
protected void processChangeWindowTitle(String label) {
35+
newLabel.set(label);
36+
}
37+
}, "ISO-8859-1"), true, "ISO-8859-1");
38+
39+
ansi.print("\033]0;un bon café\007");
40+
ansi.flush();
41+
assertEquals("un bon café", newLabel.get());
42+
}
43+
44+
@Test
45+
public void testEncodingUtf8() throws UnsupportedEncodingException {
46+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
47+
final AtomicReference<String> newLabel = new AtomicReference<String>();
48+
PrintStream ansi = new PrintStream(new AnsiNoSyncOutputStream(baos, new AnsiProcessor(baos) {
49+
@Override
50+
protected void processChangeWindowTitle(String label) {
51+
newLabel.set(label);
52+
}
53+
}, "UTF-8"), true, "UTF-8");
54+
55+
ansi.print("\033]0;ひらがな\007");
56+
ansi.flush();
57+
assertEquals("ひらがな", newLabel.get());
58+
}
59+
60+
}

0 commit comments

Comments
 (0)