Synced to post-code-review JSON printer.

pull/13171/head
Chris Fallin 10 years ago
parent a350b42069
commit 3249b36a2a
  1. 69
      upb/json/printer.c

@ -3,6 +3,9 @@
* *
* Copyright (c) 2014 Google Inc. See LICENSE for details. * Copyright (c) 2014 Google Inc. See LICENSE for details.
* Author: Josh Haberman <jhaberman@gmail.com> * Author: Josh Haberman <jhaberman@gmail.com>
*
* This currently uses snprintf() to format primitives, and could be optimized
* further.
*/ */
#include "upb/json/printer.h" #include "upb/json/printer.h"
@ -30,20 +33,41 @@ strpc *newstrpc(upb_handlers *h, const upb_fielddef *f) {
static void print_data( static void print_data(
upb_json_printer *p, const char *buf, unsigned int len) { upb_json_printer *p, const char *buf, unsigned int len) {
// TODO: Will need to change if we support pushback from the sink.
size_t n = upb_bytessink_putbuf(p->output_, p->subc_, buf, len, NULL); size_t n = upb_bytessink_putbuf(p->output_, p->subc_, buf, len, NULL);
UPB_ASSERT_VAR(n, n == len); UPB_ASSERT_VAR(n, n == len);
} }
static bool print_comma(upb_json_printer *p) { static void print_comma(upb_json_printer *p) {
if (!p->first_elem_[p->depth_]) { if (!p->first_elem_[p->depth_]) {
print_data(p, ",", 1); print_data(p, ",", 1);
} }
p->first_elem_[p->depth_] = false; p->first_elem_[p->depth_] = false;
return true;
} }
// Helpers that print properly formatted elements to the JSON output stream. // Helpers that print properly formatted elements to the JSON output stream.
// Used for escaping control chars in strings.
static const char kControlCharLimit = 0x20;
static inline bool is_json_escaped(char c) {
// See RFC 4627.
return c < kControlCharLimit || c == '"' || c == '\\';
}
static inline char* json_nice_escape(char c) {
switch (c) {
case '"': return "\\\"";
case '\\': return "\\\\";
case '\b': return "\\b";
case '\f': return "\\f";
case '\n': return "\\n";
case '\r': return "\\r";
case '\t': return "\\t";
default: return NULL;
}
}
// Write a properly quoted and escaped string. // Write a properly quoted and escaped string.
static void putstring(upb_json_printer *p, const char *buf, unsigned int len) { static void putstring(upb_json_printer *p, const char *buf, unsigned int len) {
print_data(p, "\"", 1); print_data(p, "\"", 1);
@ -52,28 +76,21 @@ static void putstring(upb_json_printer *p, const char *buf, unsigned int len) {
for (unsigned int i = 0; i < len; i++) { for (unsigned int i = 0; i < len; i++) {
char c = buf[i]; char c = buf[i];
// Handle escaping. // Handle escaping.
const char* escape = NULL; if (is_json_escaped(c)) {
char escape_buf[8]; // Use a "nice" escape, like \n, if one exists for this character.
switch (c) { const char* escape = json_nice_escape(c);
// See RFC 4627, page 5. // If we don't have a specific 'nice' escape code, use a \uXXXX-style
case '"': escape = "\\\""; break; // escape.
case '\\': escape = "\\\\"; break; char escape_buf[8];
case '\b': escape = "\\b"; break; if (!escape) {
case '\f': escape = "\\f"; break; snprintf(escape_buf, sizeof(escape_buf), "\\u%04x", (int)c);
case '\n': escape = "\\n"; break; escape = escape_buf;
case '\r': escape = "\\r"; break; }
case '\t': escape = "\\t"; break;
}
if (c < 0x20 && !escape) {
snprintf(escape_buf, sizeof(escape_buf), "\\u%04x", (int)c);
escape = escape_buf;
}
// N.B. that we assume that the input encoding is equal to the output // N.B. that we assume that the input encoding is equal to the output
// encoding (both UTF-8 for now), so for chars >= 0x20 and != \, ", we can // encoding (both UTF-8 for now), so for chars >= 0x20 and != \, ", we
// simply pass the bytes through. // can simply pass the bytes through.
if (escape) {
// If there's a current run of unescaped chars, print that run first. // If there's a current run of unescaped chars, print that run first.
if (unescaped_run) { if (unescaped_run) {
print_data(p, unescaped_run, &buf[i] - unescaped_run); print_data(p, unescaped_run, &buf[i] - unescaped_run);
@ -181,11 +198,11 @@ TYPE_HANDLERS(uint64_t, fmt_uint64);
#undef TYPE_HANDLERS #undef TYPE_HANDLERS
static void *scalar_submsg(void *closure, const void *handler_data) { static void *scalar_startsubmsg(void *closure, const void *handler_data) {
return putkey(closure, handler_data) ? closure : UPB_BREAK; return putkey(closure, handler_data) ? closure : UPB_BREAK;
} }
static void *repeated_submsg(void *closure, const void *handler_data) { static void *repeated_startsubmsg(void *closure, const void *handler_data) {
UPB_UNUSED(handler_data); UPB_UNUSED(handler_data);
upb_json_printer *p = closure; upb_json_printer *p = closure;
print_comma(p); print_comma(p);
@ -385,9 +402,9 @@ void sethandlers(const void *closure, upb_handlers *h) {
break; break;
case UPB_TYPE_MESSAGE: case UPB_TYPE_MESSAGE:
if (upb_fielddef_isseq(f)) { if (upb_fielddef_isseq(f)) {
upb_handlers_setstartsubmsg(h, f, repeated_submsg, &name_attr); upb_handlers_setstartsubmsg(h, f, repeated_startsubmsg, &name_attr);
} else { } else {
upb_handlers_setstartsubmsg(h, f, scalar_submsg, &name_attr); upb_handlers_setstartsubmsg(h, f, scalar_startsubmsg, &name_attr);
} }
break; break;
} }

Loading…
Cancel
Save