| 241 | } |
| 242 | |
| 243 | void appendSessionOutput(const char *data, size_t len) { |
| 244 | if (len == 0 || data == nullptr) return; |
| 245 | withClientLock([&]() { |
| 246 | queuedOutput.reserve(queuedOutput.length() + len); |
| 247 | String normalizedOutput = ""; |
| 248 | normalizedOutput.reserve(len); |
| 249 | for (size_t i = 0; i < len; ++i) { |
| 250 | uint8_t raw = static_cast<uint8_t>(data[i]); |
| 251 | char c = static_cast<char>(raw); |
| 252 | if (filterAnsiSequences) { |
| 253 | switch (escapeParseState) { |
| 254 | case EscapeParseState::Normal: |
| 255 | if (raw == 0x1B) { |
| 256 | escapeParseState = EscapeParseState::Esc; |
| 257 | continue; |
| 258 | } |
| 259 | break; |
| 260 | case EscapeParseState::Esc: |
| 261 | if (c == '[') { |
| 262 | escapeParseState = EscapeParseState::Csi; |
| 263 | continue; |
| 264 | } |
| 265 | if (c == ']') { |
| 266 | escapeParseState = EscapeParseState::Osc; |
| 267 | continue; |
| 268 | } |
| 269 | if (c == '(' || c == ')') { |
| 270 | escapeParseState = EscapeParseState::Charset; |
| 271 | continue; |
| 272 | } |
| 273 | escapeParseState = EscapeParseState::Normal; |
| 274 | continue; |
| 275 | case EscapeParseState::Csi: |
| 276 | if (raw >= 0x40 && raw <= 0x7E) escapeParseState = EscapeParseState::Normal; |
| 277 | continue; |
| 278 | case EscapeParseState::Osc: |
| 279 | if (raw == 0x07) escapeParseState = EscapeParseState::Normal; |
| 280 | else if (raw == 0x1B) escapeParseState = EscapeParseState::OscEsc; |
| 281 | continue; |
| 282 | case EscapeParseState::OscEsc: |
| 283 | escapeParseState = (c == '\\') ? EscapeParseState::Normal : EscapeParseState::Osc; |
| 284 | continue; |
| 285 | case EscapeParseState::Charset: escapeParseState = EscapeParseState::Normal; continue; |
| 286 | } |
| 287 | } |
| 288 | if (c == '\r') { |
| 289 | if (!queuedOutput.isEmpty() && queuedOutput[queuedOutput.length() - 1] != '\n') { |
| 290 | queuedOutput += '\n'; |
| 291 | normalizedOutput += '\n'; |
| 292 | } |
| 293 | previousOutputWasCR = true; |
| 294 | continue; |
| 295 | } |
| 296 | if (c == '\n' && previousOutputWasCR) { |
| 297 | previousOutputWasCR = false; |
| 298 | continue; |
| 299 | } |
| 300 | previousOutputWasCR = false; |
no test coverage detected