22
22
import java.io.OutputStream;
23
23
import java.io.UnsupportedEncodingException;
24
24
import java.util.ArrayList;
25
+ import java.util.Iterator;
25
26
26
27
/**
27
28
* A ANSI output stream extracts ANSI escape codes written to
@@ -214,6 +215,21 @@ private void reset(boolean skipBuffer) throws IOException {
214
215
state = LOOKING_FOR_FIRST_ESC_CHAR;
215
216
}
216
217
218
+ /**
219
+ * Helper for processEscapeCommand() to iterate over integer options
220
+ * @param optionsIterator the underlying iterator
221
+ * @throws IOException if no more non-null values left
222
+ */
223
+ private int getNextOptionInt(Iterator<Object> optionsIterator) throws IOException {
224
+ for (;;) {
225
+ if (!optionsIterator.hasNext())
226
+ throw new IllegalArgumentException();
227
+ Object arg = optionsIterator.next();
228
+ if (arg != null)
229
+ return ((Integer)arg).intValue();
230
+ }
231
+ }
232
+
217
233
/**
218
234
*
219
235
* @param options
@@ -269,7 +285,9 @@ private boolean processEscapeCommand(ArrayList<Object> options, int command) thr
269
285
}
270
286
271
287
int count = 0;
272
- for (Object next : options) {
288
+ Iterator<Object> optionsIterator = options.iterator();
289
+ while (optionsIterator.hasNext()) {
290
+ Object next = optionsIterator.next();
273
291
if (next != null) {
274
292
count++;
275
293
int value = ((Integer) next).intValue();
@@ -281,6 +299,38 @@ private boolean processEscapeCommand(ArrayList<Object> options, int command) thr
281
299
processSetForegroundColor(value - 90, true);
282
300
} else if (100 <= value && value <= 107) {
283
301
processSetBackgroundColor(value - 100, true);
302
+ } else if (value == 38 || value == 48) {
303
+ // extended color like `esc[38;5;<index>m` or `esc[38;2;<r>;<g>;<b>m`
304
+ int arg2or5 = getNextOptionInt(optionsIterator);
305
+ if (arg2or5 == 2) {
306
+ // 24 bit color style like `esc[38;2;<r>;<g>;<b>m`
307
+ int r = getNextOptionInt(optionsIterator);
308
+ int g = getNextOptionInt(optionsIterator);
309
+ int b = getNextOptionInt(optionsIterator);
310
+ if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255) {
311
+ if (value == 38)
312
+ processSetForegroundColorExt(r, g, b);
313
+ else
314
+ processSetBackgroundColorExt(r, g, b);
315
+ } else {
316
+ throw new IllegalArgumentException();
317
+ }
318
+ }
319
+ else if (arg2or5 == 5) {
320
+ // 256 color style like `esc[38;5;<index>m`
321
+ int paletteIndex = getNextOptionInt(optionsIterator);
322
+ if (paletteIndex >= 0 && paletteIndex <= 255) {
323
+ if (value == 38)
324
+ processSetForegroundColorExt(paletteIndex);
325
+ else
326
+ processSetBackgroundColorExt(paletteIndex);
327
+ } else {
328
+ throw new IllegalArgumentException();
329
+ }
330
+ }
331
+ else {
332
+ throw new IllegalArgumentException();
333
+ }
284
334
} else {
285
335
switch (value) {
286
336
case 39:
@@ -417,13 +467,25 @@ protected void processSetForegroundColor(int color) throws IOException {
417
467
protected void processSetForegroundColor(int color, boolean bright) throws IOException {
418
468
}
419
469
470
+ protected void processSetForegroundColorExt(int paletteIndex) throws IOException {
471
+ }
472
+
473
+ protected void processSetForegroundColorExt(int r, int g, int b) throws IOException {
474
+ }
475
+
420
476
protected void processSetBackgroundColor(int color) throws IOException {
421
477
processSetBackgroundColor(color, false);
422
478
}
423
479
424
480
protected void processSetBackgroundColor(int color, boolean bright) throws IOException {
425
481
}
426
482
483
+ protected void processSetBackgroundColorExt(int paletteIndex) throws IOException {
484
+ }
485
+
486
+ protected void processSetBackgroundColorExt(int r, int g, int b) throws IOException {
487
+ }
488
+
427
489
protected void processDefaultTextColor() throws IOException {
428
490
}
429
491
0 commit comments