Serenity Operating System
at master 158 lines 5.9 kB view raw
1/* 2 * Copyright (c) 2022, the SerenityOS developers. 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/Format.h> 8#include <AK/Types.h> 9#include <LibVT/EscapeSequenceParser.h> 10#include <LibVT/EscapeSequenceStateMachine.h> 11 12namespace VT { 13EscapeSequenceParser::EscapeSequenceParser(EscapeSequenceExecutor& executor) 14 : m_executor(executor) 15 , m_state_machine([this](auto action, auto byte) { perform_action(action, byte); }) 16{ 17} 18 19Vector<EscapeSequenceParser::OscParameter> EscapeSequenceParser::osc_parameters() const 20{ 21 VERIFY(m_osc_raw.size() >= m_osc_parameter_indexes.last()); 22 Vector<EscapeSequenceParser::OscParameter> params; 23 size_t prev_idx = 0; 24 for (auto end_idx : m_osc_parameter_indexes) { 25 // If the parameter is empty, we take an out of bounds index as the beginning of the Span. 26 // This should not be a problem as we won't dereference the 0-length Span that's created. 27 // Using &m_osc_raw[prev_idx] to get the start pointer checks whether we're out of bounds, 28 // so we would crash. 29 params.append({ m_osc_raw.data() + prev_idx, end_idx - prev_idx }); 30 prev_idx = end_idx; 31 } 32 return params; 33} 34 35void EscapeSequenceParser::perform_action(EscapeSequenceStateMachine::Action action, u8 byte) 36{ 37 auto advance_utf8 = [&](u8 byte) { 38 u32 new_code_point = m_code_point; 39 new_code_point <<= 6; 40 new_code_point |= byte & 0x3f; 41 return new_code_point; 42 }; 43 44 switch (action) { 45 case EscapeSequenceStateMachine::Action::_Ignore: 46 break; 47 case EscapeSequenceStateMachine::Action::Print: 48 m_executor.emit_code_point((u32)byte); 49 break; 50 case EscapeSequenceStateMachine::Action::PrintUTF8: 51 m_executor.emit_code_point(advance_utf8(byte)); 52 break; 53 case EscapeSequenceStateMachine::Action::Execute: 54 m_executor.execute_control_code(byte); 55 break; 56 case EscapeSequenceStateMachine::Action::Hook: 57 if (m_param_vector.size() == MAX_PARAMETERS) 58 m_ignoring = true; 59 else 60 m_param_vector.append(m_param); 61 m_executor.dcs_hook(m_param_vector, intermediates(), m_ignoring, byte); 62 break; 63 case EscapeSequenceStateMachine::Action::Put: 64 m_executor.receive_dcs_char(byte); 65 break; 66 case EscapeSequenceStateMachine::Action::BeginUTF8: 67 if ((byte & 0xe0) == 0xc0) { 68 m_code_point = byte & 0x1f; 69 } else if ((byte & 0xf0) == 0xe0) { 70 m_code_point = byte & 0x0f; 71 } else if ((byte & 0xf8) == 0xf0) { 72 m_code_point = byte & 0x07; 73 } else { 74 dbgln("Invalid character was parsed as UTF-8 initial byte {:02x}", byte); 75 VERIFY_NOT_REACHED(); 76 } 77 break; 78 case EscapeSequenceStateMachine::Action::AdvanceUTF8: 79 VERIFY((byte & 0xc0) == 0x80); 80 m_code_point = advance_utf8(byte); 81 break; 82 case EscapeSequenceStateMachine::Action::FailUTF8: 83 m_executor.emit_code_point(U''); 84 break; 85 case EscapeSequenceStateMachine::Action::OscStart: 86 m_osc_raw.clear(); 87 m_osc_parameter_indexes.clear(); 88 break; 89 case EscapeSequenceStateMachine::Action::OscPut: 90 if (byte == ';') { 91 if (m_osc_parameter_indexes.size() == MAX_OSC_PARAMETERS) { 92 dbgln("EscapeSequenceParser::perform_action: shenanigans! OSC sequence has too many parameters"); 93 } else { 94 m_osc_parameter_indexes.append(m_osc_raw.size()); 95 } 96 } else { 97 m_osc_raw.append(byte); 98 } 99 break; 100 case EscapeSequenceStateMachine::Action::OscEnd: 101 if (m_osc_parameter_indexes.size() == MAX_OSC_PARAMETERS) { 102 dbgln("EscapeSequenceParser::perform_action: shenanigans! OSC sequence has too many parameters"); 103 } else { 104 m_osc_parameter_indexes.append(m_osc_raw.size()); 105 } 106 m_executor.execute_osc_sequence(osc_parameters(), byte); 107 break; 108 case EscapeSequenceStateMachine::Action::Unhook: 109 m_executor.execute_dcs_sequence(); 110 break; 111 case EscapeSequenceStateMachine::Action::CsiDispatch: 112 if (m_param_vector.size() > MAX_PARAMETERS) { 113 dbgln("EscapeSequenceParser::perform_action: shenanigans! CSI sequence has too many parameters"); 114 m_ignoring = true; 115 } else { 116 m_param_vector.append(m_param); 117 } 118 119 m_executor.execute_csi_sequence(m_param_vector, intermediates(), m_ignoring, byte); 120 break; 121 122 case EscapeSequenceStateMachine::Action::EscDispatch: 123 m_executor.execute_escape_sequence(intermediates(), m_ignoring, byte); 124 break; 125 case EscapeSequenceStateMachine::Action::Collect: 126 if (m_intermediate_idx == MAX_INTERMEDIATES) { 127 dbgln("EscapeSequenceParser::perform_action: shenanigans! escape sequence has too many intermediates"); 128 m_ignoring = true; 129 } else { 130 m_intermediates[m_intermediate_idx++] = byte; 131 } 132 break; 133 case EscapeSequenceStateMachine::Action::Param: 134 if (m_param_vector.size() == MAX_PARAMETERS) { 135 dbgln("EscapeSequenceParser::perform_action: shenanigans! escape sequence has too many parameters"); 136 m_ignoring = true; 137 } else { 138 if (byte == ';') { 139 m_param_vector.append(m_param); 140 m_param = 0; 141 } else if (byte == ':') { 142 dbgln("EscapeSequenceParser::perform_action: subparameters are not yet implemented"); 143 } else { 144 m_param *= 10; 145 m_param += (byte - '0'); 146 } 147 } 148 break; 149 case EscapeSequenceStateMachine::Action::Clear: 150 m_intermediate_idx = 0; 151 m_ignoring = false; 152 153 m_param = 0; 154 m_param_vector.clear_with_capacity(); 155 break; 156 } 157} 158}