| 79 | } |
| 80 | |
| 81 | bool ParseOneDictionaryEntry(const std::string &Str, Unit *U) { |
| 82 | U->clear(); |
| 83 | if (Str.empty()) return false; |
| 84 | size_t L = 0, R = Str.size() - 1; // We are parsing the range [L,R]. |
| 85 | // Skip spaces from both sides. |
| 86 | while (L < R && isspace(Str[L])) L++; |
| 87 | while (R > L && isspace(Str[R])) R--; |
| 88 | if (R - L < 2) return false; |
| 89 | // Check the closing " |
| 90 | if (Str[R] != '"') return false; |
| 91 | R--; |
| 92 | // Find the opening " |
| 93 | while (L < R && Str[L] != '"') L++; |
| 94 | if (L >= R) return false; |
| 95 | assert(Str[L] == '\"'); |
| 96 | L++; |
| 97 | assert(L <= R); |
| 98 | for (size_t Pos = L; Pos <= R; Pos++) { |
| 99 | uint8_t V = (uint8_t)Str[Pos]; |
| 100 | if (!isprint(V) && !isspace(V)) return false; |
| 101 | if (V =='\\') { |
| 102 | // Handle '\\' |
| 103 | if (Pos + 1 <= R && (Str[Pos + 1] == '\\' || Str[Pos + 1] == '"')) { |
| 104 | U->push_back(Str[Pos + 1]); |
| 105 | Pos++; |
| 106 | continue; |
| 107 | } |
| 108 | // Handle '\xAB' |
| 109 | if (Pos + 3 <= R && Str[Pos + 1] == 'x' |
| 110 | && isxdigit(Str[Pos + 2]) && isxdigit(Str[Pos + 3])) { |
| 111 | char Hex[] = "0xAA"; |
| 112 | Hex[2] = Str[Pos + 2]; |
| 113 | Hex[3] = Str[Pos + 3]; |
| 114 | U->push_back(static_cast<uint8_t>(strtol(Hex, nullptr, 16))); |
| 115 | Pos += 3; |
| 116 | continue; |
| 117 | } |
| 118 | return false; // Invalid escape. |
| 119 | } else { |
| 120 | // Any other character. |
| 121 | U->push_back(V); |
| 122 | } |
| 123 | } |
| 124 | return true; |
| 125 | } |
| 126 | |
| 127 | bool ParseDictionaryFile(const std::string &Text, std::vector<Unit> *Units) { |
| 128 | if (Text.empty()) { |