static void json_writer_output_indent( grpc_json_writer* writer) { static const char spacesstr[] = " " " " " " " "; unsigned spaces = writer->depth * writer->indent; if (writer->indent == 0) return; if (writer->got_key) { json_writer_output_char(writer, ' '); return; } while (spaces >= (sizeof(spacesstr) - 1)) { json_writer_output_string_with_len(writer, spacesstr, sizeof(spacesstr) - 1); spaces -= (sizeof(spacesstr) - 1); } if (spaces == 0) return; json_writer_output_string_with_len( writer, spacesstr + sizeof(spacesstr) - 1 - spaces, spaces); }
static void json_writer_escape_utf16(grpc_json_writer* writer, gpr_uint16 utf16) { static const char hex[] = "0123456789abcdef"; json_writer_output_string_with_len(writer, "\\u", 2); json_writer_output_char(writer, hex[(utf16 >> 12) & 0x0f]); json_writer_output_char(writer, hex[(utf16 >> 8) & 0x0f]); json_writer_output_char(writer, hex[(utf16 >> 4) & 0x0f]); json_writer_output_char(writer, hex[(utf16) & 0x0f]); }
static void json_writer_escape_string(grpc_json_writer* writer, const char* string) { json_writer_output_char(writer, '"'); for (;;) { gpr_uint8 c = (gpr_uint8)*string++; if (c == 0) { break; } else if ((c >= 32) && (c <= 126)) { if ((c == '\\') || (c == '"')) json_writer_output_char(writer, '\\'); json_writer_output_char(writer, c); } else if ((c < 32) || (c == 127)) { switch (c) { case '\b': json_writer_output_string_with_len(writer, "\\b", 2); break; case '\f': json_writer_output_string_with_len(writer, "\\f", 2); break; case '\n': json_writer_output_string_with_len(writer, "\\n", 2); break; case '\r': json_writer_output_string_with_len(writer, "\\r", 2); break; case '\t': json_writer_output_string_with_len(writer, "\\t", 2); break; default: json_writer_escape_utf16(writer, c); break; } } else { gpr_uint32 utf32 = 0; int extra = 0; int i; int valid = 1; if ((c & 0xe0) == 0xc0) { utf32 = c & 0x1f; extra = 1; } else if ((c & 0xf0) == 0xe0) { utf32 = c & 0x0f; extra = 2; } else if ((c & 0xf8) == 0xf0) { utf32 = c & 0x07; extra = 3; } else { break; } for (i = 0; i < extra; i++) { utf32 <<= 6; c = *string++; /* Breaks out and bail on any invalid UTF-8 sequence, including \0. */ if ((c & 0xc0) != 0x80) { valid = 0; break; } utf32 |= c & 0x3f; } if (!valid) break; /* The range 0xd800 - 0xdfff is reserved by the surrogates ad vitam. * Any other range is technically reserved for future usage, so if we * don't want the software to break in the future, we have to allow * anything else. The first non-unicode character is 0x110000. */ if (((utf32 >= 0xd800) && (utf32 <= 0xdfff)) || (utf32 >= 0x110000)) break; if (utf32 >= 0x10000) { /* If utf32 contains a character that is above 0xffff, it needs to be * broken down into a utf-16 surrogate pair. A surrogate pair is first * a high surrogate, followed by a low surrogate. Each surrogate holds * 10 bits of usable data, thus allowing a total of 20 bits of data. * The high surrogate marker is 0xd800, while the low surrogate marker * is 0xdc00. The low 10 bits of each will be the usable data. * * After re-combining the 20 bits of data, one has to add 0x10000 to * the resulting value, in order to obtain the original character. * This is obviously because the range 0x0000 - 0xffff can be written * without any special trick. * * Since 0x10ffff is the highest allowed character, we're working in * the range 0x00000 - 0xfffff after we decrement it by 0x10000. * That range is exactly 20 bits. */ utf32 -= 0x10000; json_writer_escape_utf16(writer, 0xd800 | (utf32 >> 10)); json_writer_escape_utf16(writer, 0xdc00 | (utf32 & 0x3ff)); } else { json_writer_escape_utf16(writer, utf32); } }
static void json_writer_output_string(void *userdata, const char *str) { size_t len = strlen(str); json_writer_output_string_with_len(userdata, str, len); }