Serenity Operating System
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}