Commit 415e67951ba678139bb352ff33375c23eab28ca7

Authored by m-holger
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,41 +220,61 @@ JSON::unparse() const
220 std::string 220 std::string
221 JSON::encode_string(std::string const& str) 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 JSON 280 JSON