template <typename Iter>
void serialize_str(const std::string& s, Iter oi) {
+ // C0 control characters, 00-1F
+ static const char* u_map[] = {
+ "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007",
+ "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r", "\\u000e", "\\u000f",
+ "\\u0010", "\\u0011", "\\u0012", "\\u0013", "\\u0014", "\\u0015", "\\u0016", "\\u0017",
+ "\\u0018", "\\u0019", "\\u001a", "\\u001b", "\\u001c", "\\u001d", "\\u001e", "\\u001f"};
+ // To be sure we could rewrite C1 control characters also (first decode UTF-8, check, then map to
+ // \u sequence), but for now chromium allows C1 in JSON.parse
+
*oi++ = '"';
for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) {
switch (*i) {
-#define MAP(val, sym) \
- case val: \
- copy(sym, oi); \
- break
- MAP('"', "\\\"");
- MAP('\\', "\\\\");
- MAP('/', "\\/");
- MAP('\b', "\\b");
- MAP('\f', "\\f");
- MAP('\n', "\\n");
- MAP('\r', "\\r");
- MAP('\t', "\\t");
-#undef MAP
+ case '"':
+ copy("\\\"", oi);
+ break;
+ case '\\':
+ copy("\\\\", oi);
+ break;
+ case '\x7f':
+ copy("\\u007f", oi);
+ break;
default:
- if ((unsigned char)*i < 0x20 || *i == 0x7f) {
- char buf[7];
- SNPRINTF(buf, sizeof(buf), "\\u%04x", *i & 0xff);
- copy(buf, buf + 6, oi);
+ if ((unsigned char)*i < 0x20) {
+ const char* u = u_map[(unsigned char)*i];
+ while (*u) {
+ *oi++ = *u++;
+ }
} else {
*oi++ = *i;
}