EscapeFilter class final

Filters host output so that nothing reaches the renderer that leaves the device, sends data back or changes the local view on its own (24 11.2, SEC-TERM-6).

The filter works on bytes, before UTF-8 decoding: ESC and every byte of a control sequence are ASCII and never part of a UTF-8 multibyte character, so the byte view and the decoded view of the renderer see the same sequences.

Allow list (ruling of M4-35, Design note 2):

  1. Bytes outside escape sequences pass unchanged: printable text, UTF-8 multibyte, the C0 controls (BEL, BS, HT, LF, VT, FF, CR, SO, SI; the others too, xterm ignores them), DEL, and CAN and SUB when no sequence is open. 8-bit C1 bytes are not interpreted: the renderer works on decoded text and xterm does not parse C1.
  2. ESC, intermediates 0x20-0x2F and one final byte 0x30-0x7E pass (ESC 7, ESC 8, ESC D, ESC M, ESC ( B, ESC =, ESC > ...), EXCEPT the string introducers ESC P (DCS, among them DECRQSS and XTGETTCAP), ESC X (SOS), ESC ^ (PM) and ESC _ (APC): these are dropped completely with their content up to ST (ESC ); BEL does not end them.
  3. CSI (ESC [, parameters 0x30-0x3F, intermediates 0x20-0x2F, final 0x40-0x7E) passes, EXCEPT these queries and reports, dropped completely:
    • final t (window operations and reports: CSI 21 t title, CSI 20 t icon title, CSI 18 t size, CSI 14 t, and CSI 8;r;c t which would resize the local view);
    • final n unless the parameters are exactly 6 without intermediates (CPR allowed; CSI 5 n, CSI ?6 n and the others dropped);
    • final c unless the parameters are ``, 0, > or >0 without intermediates (DA1 and DA2 allowed; tertiary CSI = c dropped);
    • any intermediate $ (DECRQM CSI ? Ps $ p and the rectangle and report family);
    • final x (DECREQTPARM);
    • final q without intermediates and with a > prefix (XTVERSION); CSI Ps SP q (cursor style) passes. The answers that shells need are therefore exactly CPR (CSI 6 n) and DA1/DA2. Intermediates count for n and c because xterm ignores them: CSI 5 SP n would be a status report for it. 3a. Renderer safety (found by the red team of M4-35): a CSI is also dropped when one of its numeric parameters, read as xterm 4.0.0 reads them, exceeds maxParameterValue (REP CSI 999999999 b would freeze the view), and an SGR whose 38 or 48 lacks its colour sub-parameters (CSI 38 m, CSI 48;2 m) is dropped, because xterm reads them without a bounds check and throws; so is SGR 38;5 or 48;5 with an index above 255 (its painter reads past the palette), REP CSI Ps b with Ps above maxRepeatCount and ECH CSI 0 X (xterm erases from column -1 and throws). These are the renderer faults known for xterm 4.0.0, not a complete guard: the view must still catch exceptions of the renderer and process large output in slices.
  4. OSC (ESC ], ended by BEL or ST) is dropped completely: OSC 52 clipboard set and query, OSC 0/1/2 titles, OSC 4/10/11/12 colours with ? queries, any other. EXCEPT OSC 8, which is rewritten: ESC ] 8 ; params ; URI ST with a non-empty URI emits LinkStart (params such as id= are ignored), with an empty URI LinkEnd (only while a link is open). The link text between them passes as FilteredText, so the link is inert text plus a record. A LinkStart while a link is open first emits LinkEnd. An OSC 8 whose URI is longer than maxLinkTargetBytes or holds anything but printable ASCII (a space, a control, a line separator, a bidi control or any non-ASCII character could hide or disguise the shown target) is dropped like any other OSC and emits nothing; an open link then stays open. OSC 8 without the second ; emits nothing.
  5. CAN (0x18) or SUB (0x1A) inside a sequence aborts it; the sequence and the CAN or SUB byte are dropped. An ESC inside a sequence that is not ST aborts the sequence and starts a new one at that ESC. Further rules of the VT500 parser that keep the byte view equal to the renderer's view: a C0 control inside an ESC or CSI sequence is passed at once (executed before the sequence) and the sequence goes on; DEL inside one is dropped; a byte from 0x80 aborts it and is then handled as text; a parameter byte after an intermediate makes the CSI invalid, it is dropped up to its final byte.
  6. Memory is bounded: an ESC or CSI sequence longer than maxControlSequenceBytes is dropped up to its final byte; dropped string sequences (DCS, SOS, PM, APC, OSC other than 8 and the params of OSC 8) are consumed without buffering; only the URI of OSC 8 is buffered, up to maxLinkTargetBytes.
  7. Every sequence may be split at any byte across process calls; the result is the same as in one call.
  8. The filter never throws, logs nothing and keeps no content beyond the current sequence (15 23.4: terminal content never reaches logs).

Example:

final filter = EscapeFilter();
for (final chunk in filter.process(frame)) {
  switch (chunk) {
    case FilteredText(:final bytes): render(bytes);
    case LinkStart(:final target): openRecord(target);
    case LinkEnd(): closeRecord();
  }
}

Constructors

EscapeFilter()
Creates a filter in the ground state with no open link.

Properties

hashCode → int
The hash code for this object.
no setterinherited
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited

Methods

noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
process(List<int> bytes) → List<FilteredChunk>
Filters the next bytes of the host output.
reset() → void
Drops any partial sequence and the link state, without emitting anything.
toString() → String
A string representation of this object.
inherited

Operators

operator ==(Object other) → bool
The equality operator.
inherited

Constants

maxControlSequenceBytes → const int
The longest ESC or CSI sequence that passes, in bytes including ESC and the final byte (rule 6); real sequences stay far below it, SGR with 24-bit colours is about 20.
maxLinkTargetBytes → const int
The longest OSC 8 target URI that is kept, in bytes (rule 4 and 6); a longer one is dropped and emits nothing.
maxParameterValue → const int
The largest numeric CSI parameter that passes (rule 3a); screens, colours and modes stay below it, and xterm loops once per count for some sequences.
maxRepeatCount → const int
The largest REP (CSI Ps b) count that passes (rule 3a): one line of a wide screen. It bounds the work per sequence; it does not stop a flood of REP sequences.