| 40 | } |
| 41 | |
| 42 | static TString SanitizeString(TString s) { |
| 43 | TString escaped; |
| 44 | bool fixedSomeChars = false; |
| 45 | const unsigned char* i = reinterpret_cast<const unsigned char*>(s.data()); |
| 46 | const unsigned char* end = i + s.size(); |
| 47 | auto replaceChar = [&]() { |
| 48 | if (!fixedSomeChars) { |
| 49 | fixedSomeChars = true; |
| 50 | escaped.reserve(s.size()); |
| 51 | escaped.insert(escaped.end(), s.data(), reinterpret_cast<const char*>(i)); |
| 52 | } |
| 53 | escaped.push_back('?'); |
| 54 | }; |
| 55 | while (i < end) { |
| 56 | wchar32 rune; |
| 57 | size_t runeLen; |
| 58 | const RECODE_RESULT result = SafeReadUTF8Char(rune, runeLen, i, end); |
| 59 | if (result == RECODE_OK) { |
| 60 | if (IsAllowed(rune)) { |
| 61 | if (fixedSomeChars) { |
| 62 | escaped.insert(escaped.end(), reinterpret_cast<const char*>(i), reinterpret_cast<const char*>(i + runeLen)); |
| 63 | } |
| 64 | } else { |
| 65 | replaceChar(); |
| 66 | } |
| 67 | i += runeLen; |
| 68 | } else { |
| 69 | replaceChar(); |
| 70 | ++i; |
| 71 | } |
| 72 | } |
| 73 | if (fixedSomeChars) { |
| 74 | return escaped; |
| 75 | } else { |
| 76 | return s; |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | struct TJUnitProcessor::TOutputCapturer { |
| 81 | static constexpr int STDOUT_FD = 1; |