Skip to content

Commit

Permalink
Add a flag for disabling DCS/SOS/PM/APC recognition.
Browse files Browse the repository at this point in the history
DCS/SOS/PM/APC are terminated with an 8-bit ST, which isn't compatible
with UTF-8, so add a flag to allow users to optionally disable
recognition of these sequences.

To make room in the `Action` list, remove `Ignore` as it's effectively
the same as `None`.
  • Loading branch information
sunfishcode committed Jun 15, 2020
1 parent 07aed4a commit b99b23f
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 45 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ CHANGELOG
reported.
- Remove 8-bit C1 support. 8-bit C1 codes are now interpreted as UTF-8
continuation bytes.
- DCS/SOS/PM/APC recognition may now be disabled with the
`Parser::set_dcs_pm_apc` function. This is useful for UTF-8-only environments
where the 8-bit ST terminator is invalid.

## 0.8.0

Expand Down
2 changes: 1 addition & 1 deletion src/definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub enum Action {
EscDispatch = 4,
Execute = 5,
Hook = 6,
Ignore = 7,
CheckDcsSosPmApc = 7,
OscEnd = 8,
OscPut = 9,
OscStart = 10,
Expand Down
56 changes: 48 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
//! * OSC Strings can be terminated by 0x07
//! * Only supports 7-bit codes. Some 8-bit codes are still supported, but they no longer work in
//! all states.
//! * Support for DCS/SOS/PM/APC can be disabled.
//!
//! [`Parser`]: struct.Parser.html
//! [`Perform`]: trait.Perform.html
Expand Down Expand Up @@ -83,6 +84,7 @@ pub struct Parser {
osc_num_params: usize,
ignoring: bool,
utf8_parser: utf8::Parser,
no_dcs_sos_pm_apc: bool,
}

impl Parser {
Expand All @@ -91,6 +93,15 @@ impl Parser {
Parser::default()
}

/// Disable or enable recognition of DCS, SOS, PM, and APC sequences.
///
/// The only terminator for DCS, SOS, PM, and APC sequences is an 8-bit ST
/// code, which isn't valid UTF-8, so clients wishing to support only UTF-8
/// should use this to disable support for these sequences.
pub fn set_dcs_sos_pm_apc(&mut self, dcs_sos_pm_apc: bool) {
self.no_dcs_sos_pm_apc = !dcs_sos_pm_apc;
}

#[inline]
fn params(&self) -> &[i64] {
&self.params[..self.num_params]
Expand Down Expand Up @@ -229,6 +240,15 @@ impl Parser {
}
}

/// Reset everything on ESC/CSI/DCS entry
#[inline]
fn clear(&mut self) {
self.intermediate_idx = 0;
self.ignoring = false;
self.num_params = 0;
self.param = 0;
}

#[inline]
fn perform_action<P: Perform>(&mut self, performer: &mut P, action: Action, byte: u8) {
match action {
Expand Down Expand Up @@ -327,7 +347,7 @@ impl Parser {
Action::EscDispatch => {
performer.esc_dispatch(self.intermediates(), self.ignoring, byte)
},
Action::Ignore | Action::None => (),
Action::None => (),
Action::Collect => {
if self.intermediate_idx == MAX_INTERMEDIATES {
self.ignoring = true;
Expand Down Expand Up @@ -355,14 +375,16 @@ impl Parser {
self.param = self.param.saturating_add((byte - b'0') as i64);
}
},
Action::Clear => {
// Reset everything on ESC/CSI/DCS entry
self.intermediate_idx = 0;
self.ignoring = false;
self.num_params = 0;
self.param = 0;
},
Action::Clear => self.clear(),
Action::BeginUtf8 => self.process_utf8(performer, byte),
Action::CheckDcsSosPmApc => {
if self.no_dcs_sos_pm_apc {
self.state = State::Escape;
self.clear();
performer.esc_dispatch(self.intermediates(), self.ignoring, byte);
self.state = State::Ground;
}
},
}
}
}
Expand Down Expand Up @@ -844,6 +866,24 @@ mod tests {
assert_eq!(dispatcher.s, b"17/ab".to_vec());
}

#[test]
fn dcs_disabled() {
static INPUT: &[u8] =
&[0x1b, 0x50, 0x30, 0x3b, 0x31, 0x7c, 0x31, 0x37, 0x2f, 0x61, 0x62, 0x9c];
let mut dispatcher = EscDispatcher::default();
let mut parser = Parser::new();
parser.set_dcs_sos_pm_apc(false);

for byte in INPUT {
parser.advance(&mut dispatcher, *byte);
}

assert!(dispatcher.dispatched_esc);
assert!(dispatcher.intermediates.is_empty());
assert!(!dispatcher.ignore);
assert_eq!(dispatcher.byte, 0x50);
}

#[test]
fn exceed_max_buffer_size() {
static NUM_BYTES: usize = MAX_OSC_RAW + 100;
Expand Down
72 changes: 36 additions & 36 deletions src/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ generate_state_changes!(state_changes, {
0x00..=0x17 => (Anywhere, Execute),
0x19 => (Anywhere, Execute),
0x1c..=0x1f => (Anywhere, Execute),
0x7f => (Anywhere, Ignore),
0x7f => (Anywhere, None),
0x20..=0x2f => (EscapeIntermediate, Collect),
0x30..=0x4f => (Ground, EscDispatch),
0x51..=0x57 => (Ground, EscDispatch),
Expand All @@ -37,26 +37,26 @@ generate_state_changes!(state_changes, {
0x60..=0x7e => (Ground, EscDispatch),
0x5b => (CsiEntry, None),
0x5d => (OscString, None),
0x50 => (DcsEntry, None),
0x58 => (SosPmApcString, None),
0x5e => (SosPmApcString, None),
0x5f => (SosPmApcString, None),
0x50 => (DcsEntry, CheckDcsSosPmApc),
0x58 => (SosPmApcString, CheckDcsSosPmApc),
0x5e => (SosPmApcString, CheckDcsSosPmApc),
0x5f => (SosPmApcString, CheckDcsSosPmApc),
},

EscapeIntermediate {
0x00..=0x17 => (Anywhere, Execute),
0x19 => (Anywhere, Execute),
0x1c..=0x1f => (Anywhere, Execute),
0x20..=0x2f => (Anywhere, Collect),
0x7f => (Anywhere, Ignore),
0x7f => (Anywhere, None),
0x30..=0x7e => (Ground, EscDispatch),
},

CsiEntry {
0x00..=0x17 => (Anywhere, Execute),
0x19 => (Anywhere, Execute),
0x1c..=0x1f => (Anywhere, Execute),
0x7f => (Anywhere, Ignore),
0x7f => (Anywhere, None),
0x20..=0x2f => (CsiIntermediate, Collect),
0x3a => (CsiIgnore, None),
0x30..=0x39 => (CsiParam, Param),
Expand All @@ -69,8 +69,8 @@ generate_state_changes!(state_changes, {
0x00..=0x17 => (Anywhere, Execute),
0x19 => (Anywhere, Execute),
0x1c..=0x1f => (Anywhere, Execute),
0x20..=0x3f => (Anywhere, Ignore),
0x7f => (Anywhere, Ignore),
0x20..=0x3f => (Anywhere, None),
0x7f => (Anywhere, None),
0x40..=0x7e => (Ground, None),
},

Expand All @@ -80,7 +80,7 @@ generate_state_changes!(state_changes, {
0x1c..=0x1f => (Anywhere, Execute),
0x30..=0x39 => (Anywhere, Param),
0x3b => (Anywhere, Param),
0x7f => (Anywhere, Ignore),
0x7f => (Anywhere, None),
0x3a => (CsiIgnore, None),
0x3c..=0x3f => (CsiIgnore, None),
0x20..=0x2f => (CsiIntermediate, Collect),
Expand All @@ -92,16 +92,16 @@ generate_state_changes!(state_changes, {
0x19 => (Anywhere, Execute),
0x1c..=0x1f => (Anywhere, Execute),
0x20..=0x2f => (Anywhere, Collect),
0x7f => (Anywhere, Ignore),
0x7f => (Anywhere, None),
0x30..=0x3f => (CsiIgnore, None),
0x40..=0x7e => (Ground, CsiDispatch),
},

DcsEntry {
0x00..=0x17 => (Anywhere, Ignore),
0x19 => (Anywhere, Ignore),
0x1c..=0x1f => (Anywhere, Ignore),
0x7f => (Anywhere, Ignore),
0x00..=0x17 => (Anywhere, None),
0x19 => (Anywhere, None),
0x1c..=0x1f => (Anywhere, None),
0x7f => (Anywhere, None),
0x3a => (DcsIgnore, None),
0x20..=0x2f => (DcsIntermediate, Collect),
0x30..=0x39 => (DcsParam, Param),
Expand All @@ -111,30 +111,30 @@ generate_state_changes!(state_changes, {
},

DcsIntermediate {
0x00..=0x17 => (Anywhere, Ignore),
0x19 => (Anywhere, Ignore),
0x1c..=0x1f => (Anywhere, Ignore),
0x00..=0x17 => (Anywhere, None),
0x19 => (Anywhere, None),
0x1c..=0x1f => (Anywhere, None),
0x20..=0x2f => (Anywhere, Collect),
0x7f => (Anywhere, Ignore),
0x7f => (Anywhere, None),
0x30..=0x3f => (DcsIgnore, None),
0x40..=0x7e => (DcsPassthrough, None),
},

DcsIgnore {
0x00..=0x17 => (Anywhere, Ignore),
0x19 => (Anywhere, Ignore),
0x1c..=0x1f => (Anywhere, Ignore),
0x20..=0x7f => (Anywhere, Ignore),
0x00..=0x17 => (Anywhere, None),
0x19 => (Anywhere, None),
0x1c..=0x1f => (Anywhere, None),
0x20..=0x7f => (Anywhere, None),
0x9c => (Ground, None),
},

DcsParam {
0x00..=0x17 => (Anywhere, Ignore),
0x19 => (Anywhere, Ignore),
0x1c..=0x1f => (Anywhere, Ignore),
0x00..=0x17 => (Anywhere, None),
0x19 => (Anywhere, None),
0x1c..=0x1f => (Anywhere, None),
0x30..=0x39 => (Anywhere, Param),
0x3b => (Anywhere, Param),
0x7f => (Anywhere, Ignore),
0x7f => (Anywhere, None),
0x3a => (DcsIgnore, None),
0x3c..=0x3f => (DcsIgnore, None),
0x20..=0x2f => (DcsIntermediate, Collect),
Expand All @@ -146,24 +146,24 @@ generate_state_changes!(state_changes, {
0x19 => (Anywhere, Put),
0x1c..=0x1f => (Anywhere, Put),
0x20..=0x7e => (Anywhere, Put),
0x7f => (Anywhere, Ignore),
0x7f => (Anywhere, None),
0x9c => (Ground, None),
},

SosPmApcString {
0x00..=0x17 => (Anywhere, Ignore),
0x19 => (Anywhere, Ignore),
0x1c..=0x1f => (Anywhere, Ignore),
0x20..=0x7f => (Anywhere, Ignore),
0x00..=0x17 => (Anywhere, None),
0x19 => (Anywhere, None),
0x1c..=0x1f => (Anywhere, None),
0x20..=0x7f => (Anywhere, None),
0x9c => (Ground, None),
},

OscString {
0x00..=0x06 => (Anywhere, Ignore),
0x00..=0x06 => (Anywhere, None),
0x07 => (Ground, None),
0x08..=0x17 => (Anywhere, Ignore),
0x19 => (Anywhere, Ignore),
0x1c..=0x1f => (Anywhere, Ignore),
0x08..=0x17 => (Anywhere, None),
0x19 => (Anywhere, None),
0x1c..=0x1f => (Anywhere, None),
0x20..=0xff => (Anywhere, OscPut),
}
});

0 comments on commit b99b23f

Please sign in to comment.