diff --git a/src/definitions.rs b/src/definitions.rs index 218c1eb..6857e2f 100644 --- a/src/definitions.rs +++ b/src/definitions.rs @@ -19,7 +19,7 @@ pub enum State { #[default] Ground = 12, OscString = 13, - SosPmApcString = 14, + Null = 14, Utf8 = 15, } @@ -35,9 +35,9 @@ pub enum Action { Execute = 5, Hook = 6, Ignore = 7, - OscEnd = 8, - OscPut = 9, - OscStart = 10, + StringEnd = 8, + StringPut = 9, + StringStart = 10, Param = 11, Print = 12, Put = 13, @@ -76,7 +76,7 @@ mod tests { #[test] fn unpack_state_action() { match unpack(0xee) { - (State::SosPmApcString, Action::Unhook) => (), + (State::Null, Action::Unhook) => (), _ => panic!("unpack failed"), } @@ -94,7 +94,7 @@ mod tests { #[test] fn pack_state_action() { match unpack(0xee) { - (State::SosPmApcString, Action::Unhook) => (), + (State::Null, Action::Unhook) => (), _ => panic!("unpack failed"), } diff --git a/src/lib.rs b/src/lib.rs index 31e2a31..e40b66e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -89,6 +89,7 @@ pub struct Parser { osc_num_params: usize, ignoring: bool, utf8_parser: utf8::Parser, + str_start: u8, } impl Parser { @@ -185,7 +186,7 @@ impl Parser { self.perform_action(performer, Action::Unhook, byte); }, State::OscString => { - self.perform_action(performer, Action::OscEnd, byte); + self.perform_action(performer, Action::StringEnd, byte); }, _ => (), } @@ -200,7 +201,7 @@ impl Parser { self.perform_action(performer, Action::Hook, byte); }, State::OscString => { - self.perform_action(performer, Action::OscStart, byte); + self.perform_action(performer, Action::StringStart, byte); }, _ => (), } @@ -231,6 +232,21 @@ impl Parser { } } + #[inline] + fn apc_dispatch(&self, performer: &mut P) { + performer.apc_dispatch(&self.osc_raw); + } + + #[inline] + fn pm_dispatch(&self, performer: &mut P) { + performer.pm_dispatch(&self.osc_raw); + } + + #[inline] + fn sos_dispatch(&self, performer: &mut P) { + performer.sos_dispatch(&self.osc_raw); + } + #[inline] fn perform_action(&mut self, performer: &mut P, action: Action, byte: u8) { match action { @@ -246,11 +262,12 @@ impl Parser { performer.hook(self.params(), self.intermediates(), self.ignoring, byte as char); }, Action::Put => performer.put(byte), - Action::OscStart => { + Action::StringStart => { + self.str_start = byte % 64; self.osc_raw.clear(); self.osc_num_params = 0; }, - Action::OscPut => { + Action::StringPut => { #[cfg(feature = "no_std")] { if self.osc_raw.is_full() { @@ -261,7 +278,7 @@ impl Parser { let idx = self.osc_raw.len(); // Param separator - if byte == b';' { + if self.str_start == 0x1d && byte == b';' { let param_idx = self.osc_num_params; match param_idx { // Only process up to MAX_OSC_PARAMS @@ -285,29 +302,45 @@ impl Parser { self.osc_raw.push(byte); } }, - Action::OscEnd => { + Action::StringEnd => { let param_idx = self.osc_num_params; let idx = self.osc_raw.len(); - match param_idx { - // Finish last parameter if not already maxed - MAX_OSC_PARAMS => (), - - // First param is special - 0 to current byte index - 0 => { - self.osc_params[param_idx] = (0, idx); - self.osc_num_params += 1; + match self.str_start { + 0x1d => { + match param_idx { + // Finish last parameter if not already maxed + MAX_OSC_PARAMS => (), + + // First param is special - 0 to current byte index + 0 => { + self.osc_params[param_idx] = (0, idx); + self.osc_num_params += 1; + }, + + // All other params depend on previous indexing + _ => { + let prev = self.osc_params[param_idx - 1]; + let begin = prev.1; + self.osc_params[param_idx] = (begin, idx); + self.osc_num_params += 1; + }, + } + self.osc_dispatch(performer, byte); }, - - // All other params depend on previous indexing - _ => { - let prev = self.osc_params[param_idx - 1]; - let begin = prev.1; - self.osc_params[param_idx] = (begin, idx); - self.osc_num_params += 1; + 0x18 => { + self.sos_dispatch(performer); + }, + 0x1e => { + self.pm_dispatch(performer); + }, + 0x1F => { + self.apc_dispatch(performer); }, + // This condition should never be hit under the + // current way in which the code is ran. + _ => unreachable!(), } - self.osc_dispatch(performer, byte); }, Action::Unhook => performer.unhook(), Action::CsiDispatch => { @@ -428,6 +461,18 @@ pub trait Perform { /// The `ignore` flag indicates that more than two intermediates arrived and /// subsequent characters were ignored. fn esc_dispatch(&mut self, _intermediates: &[u8], _ignore: bool, _byte: u8) {} + + /// Called at the end of an APC (application program command), where + /// `bytes` is the content of the APC. + fn apc_dispatch(&mut self, _bytes: &[u8]) {} + + /// Called at the end of an SOS (start of string), where + /// `bytes` is the content of the SOS. + fn sos_dispatch(&mut self, _bytes: &[u8]) {} + + /// Called at the end of a PM (privacy message), where + /// `bytes` is the content of the PM. + fn pm_dispatch(&mut self, _bytes: &[u8]) {} } #[cfg(all(test, feature = "no_std"))] @@ -460,6 +505,9 @@ mod tests { DcsHook(Vec>, Vec, bool, char), DcsPut(u8), DcsUnhook, + Apc(Vec), + Pm(Vec), + Sos(Vec), } impl Perform for Dispatcher { @@ -492,6 +540,18 @@ mod tests { fn unhook(&mut self) { self.dispatched.push(Sequence::DcsUnhook); } + + fn apc_dispatch(&mut self, bytes: &[u8]) { + self.dispatched.push(Sequence::Apc(bytes.to_vec())) + } + + fn sos_dispatch(&mut self, bytes: &[u8]) { + self.dispatched.push(Sequence::Sos(bytes.to_vec())) + } + + fn pm_dispatch(&mut self, bytes: &[u8]) { + self.dispatched.push(Sequence::Pm(bytes.to_vec())) + } } #[test] @@ -880,6 +940,59 @@ mod tests { assert_eq!(dispatcher.dispatched[6], Sequence::DcsUnhook); } + #[test] + fn parse_apc() { + const INPUT: &[u8] = b"\x1b_abc\x1b\\"; + + // Test with ESC \ terminator. + + let mut dispatcher = Dispatcher::default(); + let mut parser = Parser::new(); + + for byte in INPUT { + parser.advance(&mut dispatcher, *byte); + } + assert_eq!( + dispatcher.dispatched, + vec![Sequence::Apc(b"abc".to_vec()), Sequence::Esc(vec![], false, 92)] + ) + } + #[test] + fn parse_pm() { + const INPUT: &[u8] = b"\x1b^abc\x1b\\"; + + // Test with ESC \ terminator. + + let mut dispatcher = Dispatcher::default(); + let mut parser = Parser::new(); + + for byte in INPUT { + parser.advance(&mut dispatcher, *byte); + } + assert_eq!( + dispatcher.dispatched, + vec![Sequence::Pm(b"abc".to_vec()), Sequence::Esc(vec![], false, 92)] + ) + } + + #[test] + fn parse_sos() { + const INPUT: &[u8] = b"\x1bXabc\x1b\\"; + + // Test with ESC \ terminator. + + let mut dispatcher = Dispatcher::default(); + let mut parser = Parser::new(); + + for byte in INPUT { + parser.advance(&mut dispatcher, *byte); + } + assert_eq!( + dispatcher.dispatched, + vec![Sequence::Sos(b"abc".to_vec()), Sequence::Esc(vec![], false, 92)] + ) + } + #[test] fn intermediate_reset_on_dcs_exit() { static INPUT: &[u8] = b"\x1bP=1sZZZ\x1b+\x5c"; diff --git a/src/table.rs b/src/table.rs index f2c0105..42a713a 100644 --- a/src/table.rs +++ b/src/table.rs @@ -44,9 +44,9 @@ generate_state_changes!(state_changes, { 0x5b => (CsiEntry, None), 0x5d => (OscString, None), 0x50 => (DcsEntry, None), - 0x58 => (SosPmApcString, None), - 0x5e => (SosPmApcString, None), - 0x5f => (SosPmApcString, None), + 0x58 => (OscString, None), + 0x5e => (OscString, None), + 0x5f => (OscString, None), }, EscapeIntermediate { @@ -152,12 +152,8 @@ generate_state_changes!(state_changes, { 0x9c => (Ground, None), }, - SosPmApcString { - 0x00..=0x17 => (Anywhere, Ignore), - 0x19 => (Anywhere, Ignore), - 0x1c..=0x1f => (Anywhere, Ignore), - 0x20..=0x7f => (Anywhere, Ignore), - 0x9c => (Ground, None), + Null { + 0x00..=0xFF => (Anywhere, Ignore), }, OscString { @@ -166,6 +162,6 @@ generate_state_changes!(state_changes, { 0x08..=0x17 => (Anywhere, Ignore), 0x19 => (Anywhere, Ignore), 0x1c..=0x1f => (Anywhere, Ignore), - 0x20..=0xff => (Anywhere, OscPut), + 0x20..=0xff => (Anywhere, StringPut), } });