Commit 415e67951ba678139bb352ff33375c23eab28ca7
Committed by
Jay Berkenbilt
1 parent
1787d850
Refactor JSON::encode_string
Showing
1 changed file
with
52 additions
and
32 deletions
libqpdf/JSON.cc
| ... | ... | @@ -220,41 +220,61 @@ JSON::unparse() const |
| 220 | 220 | std::string |
| 221 | 221 | JSON::encode_string(std::string const& str) |
| 222 | 222 | { |
| 223 | - std::string result; | |
| 224 | - size_t len = str.length(); | |
| 225 | - for (size_t i = 0; i < len; ++i) { | |
| 226 | - unsigned char ch = static_cast<unsigned char>(str.at(i)); | |
| 227 | - switch (ch) { | |
| 228 | - case '\\': | |
| 229 | - result += "\\\\"; | |
| 230 | - break; | |
| 231 | - case '\"': | |
| 232 | - result += "\\\""; | |
| 233 | - break; | |
| 234 | - case '\b': | |
| 235 | - result += "\\b"; | |
| 236 | - break; | |
| 237 | - case '\f': | |
| 238 | - result += "\\f"; | |
| 239 | - break; | |
| 240 | - case '\n': | |
| 241 | - result += "\\n"; | |
| 242 | - break; | |
| 243 | - case '\r': | |
| 244 | - result += "\\r"; | |
| 245 | - break; | |
| 246 | - case '\t': | |
| 247 | - result += "\\t"; | |
| 248 | - break; | |
| 249 | - default: | |
| 250 | - if (ch < 32) { | |
| 251 | - result += "\\u" + QUtil::int_to_string_base(ch, 16, 4); | |
| 252 | - } else { | |
| 253 | - result.append(1, static_cast<char>(ch)); | |
| 223 | + static auto constexpr hexchars = "0123456789abcdef"; | |
| 224 | + | |
| 225 | + auto begin = str.cbegin(); | |
| 226 | + auto end = str.cend(); | |
| 227 | + auto iter = begin; | |
| 228 | + while (iter != end) { | |
| 229 | + auto c = static_cast<unsigned char>(*iter); | |
| 230 | + if ((c > 34 && c != '\\') || c == ' ' || c == 33) { | |
| 231 | + // Optimistically check that no char in str requires escaping. | |
| 232 | + // Hopefully we can just return the input str. | |
| 233 | + ++iter; | |
| 234 | + } else { | |
| 235 | + // We found a char that requires escaping. Initialize result to the | |
| 236 | + // chars scanned so far, append/replace the rest of str one char at | |
| 237 | + // a time, and return the result. | |
| 238 | + std::string result{begin, iter}; | |
| 239 | + | |
| 240 | + for (; iter != end; ++iter) { | |
| 241 | + auto ch = static_cast<unsigned char>(*iter); | |
| 242 | + if ((ch > 34 && ch != '\\') || ch == ' ' || ch == 33) { | |
| 243 | + // Check for most common case first. | |
| 244 | + result += *iter; | |
| 245 | + } else { | |
| 246 | + switch (ch) { | |
| 247 | + case '\\': | |
| 248 | + result += "\\\\"; | |
| 249 | + break; | |
| 250 | + case '\"': | |
| 251 | + result += "\\\""; | |
| 252 | + break; | |
| 253 | + case '\b': | |
| 254 | + result += "\\b"; | |
| 255 | + break; | |
| 256 | + case '\f': | |
| 257 | + result += "\\f"; | |
| 258 | + break; | |
| 259 | + case '\n': | |
| 260 | + result += "\\n"; | |
| 261 | + break; | |
| 262 | + case '\r': | |
| 263 | + result += "\\r"; | |
| 264 | + break; | |
| 265 | + case '\t': | |
| 266 | + result += "\\t"; | |
| 267 | + break; | |
| 268 | + default: | |
| 269 | + result += ch < 16 ? "\\u000" : "\\u001"; | |
| 270 | + result += hexchars[ch % 16]; | |
| 271 | + } | |
| 272 | + } | |
| 254 | 273 | } |
| 274 | + return result; | |
| 255 | 275 | } |
| 256 | 276 | } |
| 257 | - return result; | |
| 277 | + return str; | |
| 258 | 278 | } |
| 259 | 279 | |
| 260 | 280 | JSON | ... | ... |