]> git.proxmox.com Git - mirror_ovs.git/blobdiff - lib/json.c
cirrus: Use FreeBSD 12.2.
[mirror_ovs.git] / lib / json.c
index 3acaa1964d3d5b2fe66291819dc423bb36d0a210..32d25003b81098ae442119de179843fbd2d326b8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009 Nicira Networks.
+ * Copyright (c) 2009-2012, 2014-2017 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 #include <config.h>
 
-#include "json.h"
+#include "openvswitch/json.h"
 
-#include <assert.h>
 #include <ctype.h>
 #include <errno.h>
 #include <float.h>
 #include <limits.h>
-#include <math.h>
 #include <string.h>
 
-#include "dynamic-string.h"
+#include "openvswitch/dynamic-string.h"
 #include "hash.h"
-#include "shash.h"
+#include "openvswitch/shash.h"
 #include "unicode.h"
 #include "util.h"
+#include "uuid.h"
 
 /* The type of a JSON token. */
 enum json_token_type {
@@ -60,7 +59,7 @@ struct json_token {
         double real;
         long long int integer;
         const char *string;
-    } u;
+    };
 };
 
 enum json_lex_state {
@@ -119,7 +118,7 @@ static struct json *json_create(enum json_type type);
 static void json_parser_input(struct json_parser *, struct json_token *);
 
 static void json_error(struct json_parser *p, const char *format, ...)
-    PRINTF_FORMAT(2, 3);
+    OVS_PRINTF_FORMAT(2, 3);
 \f
 const char *
 json_type_to_string(enum json_type type)
@@ -171,7 +170,7 @@ struct json *
 json_string_create_nocopy(char *s)
 {
     struct json *json = json_create(JSON_STRING);
-    json->u.string = s;
+    json->string = s;
     return json;
 }
 
@@ -185,9 +184,9 @@ struct json *
 json_array_create_empty(void)
 {
     struct json *json = json_create(JSON_ARRAY);
-    json->u.array.elems = NULL;
-    json->u.array.n = 0;
-    json->u.array.n_allocated = 0;
+    json->array.elems = NULL;
+    json->array.n = 0;
+    json->array.n_allocated = 0;
     return json;
 }
 
@@ -216,9 +215,9 @@ struct json *
 json_array_create(struct json **elements, size_t n)
 {
     struct json *json = json_create(JSON_ARRAY);
-    json->u.array.elems = elements;
-    json->u.array.n = n;
-    json->u.array.n_allocated = n;
+    json->array.elems = elements;
+    json->array.n = n;
+    json->array.n_allocated = n;
     return json;
 }
 
@@ -253,8 +252,8 @@ struct json *
 json_object_create(void)
 {
     struct json *json = json_create(JSON_OBJECT);
-    json->u.object = xmalloc(sizeof *json->u.object);
-    shash_init(json->u.object);
+    json->object = xmalloc(sizeof *json->object);
+    shash_init(json->object);
     return json;
 }
 
@@ -262,7 +261,7 @@ struct json *
 json_integer_create(long long int integer)
 {
     struct json *json = json_create(JSON_INTEGER);
-    json->u.integer = integer;
+    json->integer = integer;
     return json;
 }
 
@@ -270,14 +269,20 @@ struct json *
 json_real_create(double real)
 {
     struct json *json = json_create(JSON_REAL);
-    json->u.real = real;
+    json->real = real;
     return json;
 }
 
 void
 json_object_put(struct json *json, const char *name, struct json *value)
 {
-    shash_add(json->u.object, name, value);
+    json_destroy(shash_replace(json->object, name, value));
+}
+
+void
+json_object_put_nocopy(struct json *json, char *name, struct json *value)
+{
+    json_destroy(shash_replace_nocopy(json->object, name, value));
 }
 
 void
@@ -286,46 +291,57 @@ json_object_put_string(struct json *json, const char *name, const char *value)
     json_object_put(json, name, json_string_create(value));
 }
 
+void OVS_PRINTF_FORMAT(3, 4)
+json_object_put_format(struct json *json,
+                       const char *name, const char *format, ...)
+{
+    va_list args;
+    va_start(args, format);
+    json_object_put(json, name,
+                    json_string_create_nocopy(xvasprintf(format, args)));
+    va_end(args);
+}
+
 const char *
 json_string(const struct json *json)
 {
-    assert(json->type == JSON_STRING);
-    return json->u.string;
+    ovs_assert(json->type == JSON_STRING);
+    return json->string;
 }
 
 struct json_array *
 json_array(const struct json *json)
 {
-    assert(json->type == JSON_ARRAY);
-    return (struct json_array *) &json->u.array;
+    ovs_assert(json->type == JSON_ARRAY);
+    return CONST_CAST(struct json_array *, &json->array);
 }
 
 struct shash *
 json_object(const struct json *json)
 {
-    assert(json->type == JSON_OBJECT);
-    return (struct shash *) json->u.object;
+    ovs_assert(json->type == JSON_OBJECT);
+    return CONST_CAST(struct shash *, json->object);
 }
 
 bool
 json_boolean(const struct json *json)
 {
-    assert(json->type == JSON_TRUE || json->type == JSON_FALSE);
+    ovs_assert(json->type == JSON_TRUE || json->type == JSON_FALSE);
     return json->type == JSON_TRUE;
 }
 
 double
 json_real(const struct json *json)
 {
-    assert(json->type == JSON_REAL || json->type == JSON_INTEGER);
-    return json->type == JSON_REAL ? json->u.real : json->u.integer;
+    ovs_assert(json->type == JSON_REAL || json->type == JSON_INTEGER);
+    return json->type == JSON_REAL ? json->real : json->integer;
 }
 
 int64_t
 json_integer(const struct json *json)
 {
-    assert(json->type == JSON_INTEGER);
-    return json->u.integer;
+    ovs_assert(json->type == JSON_INTEGER);
+    return json->integer;
 }
 \f
 static void json_destroy_object(struct shash *object);
@@ -335,18 +351,18 @@ static void json_destroy_array(struct json_array *array);
 void
 json_destroy(struct json *json)
 {
-    if (json) {
+    if (json && !--json->count) {
         switch (json->type) {
         case JSON_OBJECT:
-            json_destroy_object(json->u.object);
+            json_destroy_object(json->object);
             break;
 
         case JSON_ARRAY:
-            json_destroy_array(&json->u.array);
+            json_destroy_array(&json->array);
             break;
 
         case JSON_STRING:
-            free(json->u.string);
+            free(json->string);
             break;
 
         case JSON_NULL:
@@ -357,7 +373,7 @@ json_destroy(struct json *json)
             break;
 
         case JSON_N_TYPES:
-            NOT_REACHED();
+            OVS_NOT_REACHED();
         }
         free(json);
     }
@@ -394,17 +410,17 @@ static struct json *json_clone_array(const struct json_array *array);
 
 /* Returns a deep copy of 'json'. */
 struct json *
-json_clone(const struct json *json)
+json_deep_clone(const struct json *json)
 {
     switch (json->type) {
     case JSON_OBJECT:
-        return json_clone_object(json->u.object);
+        return json_clone_object(json->object);
 
     case JSON_ARRAY:
-        return json_clone_array(&json->u.array);
+        return json_clone_array(&json->array);
 
     case JSON_STRING:
-        return json_string_create(json->u.string);
+        return json_string_create(json->string);
 
     case JSON_NULL:
     case JSON_FALSE:
@@ -412,17 +428,32 @@ json_clone(const struct json *json)
         return json_create(json->type);
 
     case JSON_INTEGER:
-        return json_integer_create(json->u.integer);
+        return json_integer_create(json->integer);
 
     case JSON_REAL:
-        return json_real_create(json->u.real);
+        return json_real_create(json->real);
 
     case JSON_N_TYPES:
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 
+/* Returns 'json', with the reference count incremented. */
+struct json *
+json_clone(const struct json *json_)
+{
+    struct json *json = CONST_CAST(struct json *, json_);
+    json->count++;
+    return json;
+}
+
+struct json *
+json_nullable_clone(const struct json *json)
+{
+    return json ? json_clone(json) : NULL;
+}
+
 static struct json *
 json_clone_object(const struct shash *object)
 {
@@ -463,6 +494,7 @@ json_hash_object(const struct shash *object, size_t basis)
         basis = hash_string(node->name, basis);
         basis = json_hash(node->data, basis);
     }
+    free(nodes);
     return basis;
 }
 
@@ -483,13 +515,13 @@ json_hash(const struct json *json, size_t basis)
 {
     switch (json->type) {
     case JSON_OBJECT:
-        return json_hash_object(json->u.object, basis);
+        return json_hash_object(json->object, basis);
 
     case JSON_ARRAY:
-        return json_hash_array(&json->u.array, basis);
+        return json_hash_array(&json->array, basis);
 
     case JSON_STRING:
-        return hash_string(json->u.string, basis);
+        return hash_string(json->string, basis);
 
     case JSON_NULL:
     case JSON_FALSE:
@@ -497,14 +529,14 @@ json_hash(const struct json *json, size_t basis)
         return hash_int(json->type << 8, basis);
 
     case JSON_INTEGER:
-        return hash_int(json->u.integer, basis);
+        return hash_int(json->integer, basis);
 
     case JSON_REAL:
-        return hash_double(json->u.real, basis);
+        return hash_double(json->real, basis);
 
     case JSON_N_TYPES:
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 
@@ -548,19 +580,23 @@ json_equal_array(const struct json_array *a, const struct json_array *b)
 bool
 json_equal(const struct json *a, const struct json *b)
 {
-    if (a->type != b->type) {
+    if (a == b) {
+        return true;
+    } else if (!a || !b) {
+        return false;
+    } else if (a->type != b->type) {
         return false;
     }
 
     switch (a->type) {
     case JSON_OBJECT:
-        return json_equal_object(a->u.object, b->u.object);
+        return json_equal_object(a->object, b->object);
 
     case JSON_ARRAY:
-        return json_equal_array(&a->u.array, &b->u.array);
+        return json_equal_array(&a->array, &b->array);
 
     case JSON_STRING:
-        return !strcmp(a->u.string, b->u.string);
+        return !strcmp(a->string, b->string);
 
     case JSON_NULL:
     case JSON_FALSE:
@@ -568,14 +604,14 @@ json_equal(const struct json *a, const struct json *b)
         return true;
 
     case JSON_INTEGER:
-        return a->u.integer == b->u.integer;
+        return a->integer == b->integer;
 
     case JSON_REAL:
-        return a->u.real == b->u.real;
+        return a->real == b->real;
 
     case JSON_N_TYPES:
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 \f
@@ -607,7 +643,6 @@ json_lex_number(struct json_parser *p)
     const char *cp = ds_cstr(&p->buffer);
     unsigned long long int significand = 0;
     struct json_token token;
-    int sig_digits = 0;
     bool imprecise = false;
     bool negative = false;
     int pow10 = 0;
@@ -621,18 +656,16 @@ json_lex_number(struct json_parser *p)
     /* At least one integer digit, but 0 may not be used as a leading digit for
      * a longer number. */
     significand = 0;
-    sig_digits = 0;
     if (*cp == '0') {
         cp++;
-        if (isdigit(*cp)) {
+        if (isdigit((unsigned char) *cp)) {
             json_error(p, "leading zeros not allowed");
             return;
         }
-    } else if (isdigit(*cp)) {
+    } else if (isdigit((unsigned char) *cp)) {
         do {
             if (significand <= ULLONG_MAX / 10) {
                 significand = significand * 10 + (*cp - '0');
-                sig_digits++;
             } else {
                 pow10++;
                 if (*cp != '0') {
@@ -640,7 +673,7 @@ json_lex_number(struct json_parser *p)
                 }
             }
             cp++;
-        } while (isdigit(*cp));
+        } while (isdigit((unsigned char) *cp));
     } else {
         json_error(p, "'-' must be followed by digit");
         return;
@@ -649,20 +682,19 @@ json_lex_number(struct json_parser *p)
     /* Optional fraction. */
     if (*cp == '.') {
         cp++;
-        if (!isdigit(*cp)) {
+        if (!isdigit((unsigned char) *cp)) {
             json_error(p, "decimal point must be followed by digit");
             return;
         }
         do {
             if (significand <= ULLONG_MAX / 10) {
                 significand = significand * 10 + (*cp - '0');
-                sig_digits++;
                 pow10--;
             } else if (*cp != '0') {
                 imprecise = true;
             }
             cp++;
-        } while (isdigit(*cp));
+        } while (isdigit((unsigned char) *cp));
     }
 
     /* Optional exponent. */
@@ -678,7 +710,7 @@ json_lex_number(struct json_parser *p)
             cp++;
         }
 
-        if (!isdigit(*cp)) {
+        if (!isdigit((unsigned char) *cp)) {
             json_error(p, "exponent must contain at least one digit");
             return;
         }
@@ -686,16 +718,21 @@ json_lex_number(struct json_parser *p)
         exponent = 0;
         do {
             if (exponent >= INT_MAX / 10) {
-                json_error(p, "exponent outside valid range");
-                return;
+                goto bad_exponent;
             }
             exponent = exponent * 10 + (*cp - '0');
             cp++;
-        } while (isdigit(*cp));
+        } while (isdigit((unsigned char) *cp));
 
         if (negative_exponent) {
+            if (pow10 < INT_MIN + exponent) {
+                goto bad_exponent;
+            }
             pow10 -= exponent;
         } else {
+            if (pow10 > INT_MAX - exponent) {
+                goto bad_exponent;
+            }
             pow10 += exponent;
         }
     }
@@ -709,9 +746,8 @@ json_lex_number(struct json_parser *p)
      *
      * We suppress negative zeros as a matter of policy. */
     if (!significand) {
-        struct json_token token;
         token.type = T_INTEGER;
-        token.u.integer = 0;
+        token.integer = 0;
         json_parser_input(p, &token);
         return;
     }
@@ -719,12 +755,10 @@ json_lex_number(struct json_parser *p)
     if (!imprecise) {
         while (pow10 > 0 && significand < ULLONG_MAX / 10) {
             significand *= 10;
-            sig_digits++;
             pow10--;
         }
         while (pow10 < 0 && significand % 10 == 0) {
             significand /= 10;
-            sig_digits--;
             pow10++;
         }
         if (pow10 == 0
@@ -732,148 +766,203 @@ json_lex_number(struct json_parser *p)
                                ? (unsigned long long int) LLONG_MAX + 1
                                : LLONG_MAX)) {
             token.type = T_INTEGER;
-            token.u.integer = negative ? -significand : significand;
+            token.integer = negative ? -significand : significand;
             json_parser_input(p, &token);
             return;
         }
     }
 
     token.type = T_REAL;
-    if (!str_to_double(ds_cstr(&p->buffer), &token.u.real)) {
+    if (!str_to_double(ds_cstr(&p->buffer), &token.real)) {
         json_error(p, "number outside valid range");
         return;
     }
     /* Suppress negative zero. */
-    if (token.u.real == 0) {
-        token.u.real = 0;
+    if (token.real == 0) {
+        token.real = 0;
     }
     json_parser_input(p, &token);
+    return;
+
+bad_exponent:
+    json_error(p, "exponent outside valid range");
 }
 
-static bool
-json_lex_4hex(struct json_parser *p, const char *cp, int *valuep)
+static const char *
+json_lex_4hex(const char *cp, const char *end, int *valuep)
 {
-    int value, i;
+    unsigned int value;
+    bool ok;
 
-    value = 0;
-    for (i = 0; i < 4; i++) {
-        unsigned char c = *cp++;
-        if (!isxdigit(c)) {
-            json_error(p, "malformed \\u escape");
-            return false;
-        }
-        value = (value << 4) | hexit_value(c);
+    if (cp + 4 > end) {
+        return "quoted string ends within \\u escape";
+    }
+
+    value = hexits_value(cp, 4, &ok);
+    if (!ok) {
+        return "malformed \\u escape";
     }
     if (!value) {
-        json_error(p, "null bytes not supported in quoted strings");
-        return false;
+        return "null bytes not supported in quoted strings";
     }
     *valuep = value;
-    return true;
+    return NULL;
 }
 
 static const char *
-json_lex_unicode(struct json_parser *p, const char *cp, struct ds *s)
+json_lex_unicode(const char *cp, const char *end, struct ds *out)
 {
+    const char *error;
     int c0, c1;
 
-    if (!json_lex_4hex(p, cp, &c0)) {
+    error = json_lex_4hex(cp, end, &c0);
+    if (error) {
+        ds_clear(out);
+        ds_put_cstr(out, error);
         return NULL;
     }
     cp += 4;
     if (!uc_is_leading_surrogate(c0)) {
-        ds_put_utf8(s, c0);
+        ds_put_utf8(out, c0);
         return cp;
     }
 
-    if (*cp++ != '\\' || *cp++ != 'u') {
-        json_error(p, "malformed escaped surrogate pair");
+    if (cp + 2 > end || *cp++ != '\\' || *cp++ != 'u') {
+        ds_clear(out);
+        ds_put_cstr(out, "malformed escaped surrogate pair");
         return NULL;
     }
 
-    if (!json_lex_4hex(p, cp, &c1)) {
+    error = json_lex_4hex(cp, end, &c1);
+    if (error) {
+        ds_clear(out);
+        ds_put_cstr(out, error);
         return NULL;
     }
     cp += 4;
     if (!uc_is_trailing_surrogate(c1)) {
-        json_error(p, "second half of escaped surrogate pair is not "
-                   "trailing surrogate");
+        ds_clear(out);
+        ds_put_cstr(out, "second half of escaped surrogate pair is not "
+                    "trailing surrogate");
         return NULL;
     }
 
-    ds_put_utf8(s, utf16_decode_surrogate_pair(c0, c1));
+    ds_put_utf8(out, utf16_decode_surrogate_pair(c0, c1));
     return cp;
 }
 
-static void
-json_lex_string(struct json_parser *p)
-{
-    struct json_token token;
-    const char *cp;
-    struct ds s;
-
-    cp = ds_cstr(&p->buffer);
-    if (!strchr(cp, '\\')) {
-        token.type = T_STRING;
-        token.u.string = cp;
-        json_parser_input(p, &token);
-        return;
-    }
-
-    ds_init(&s);
-    ds_reserve(&s, strlen(cp));
-    while (*cp != '\0') {
-        if (*cp != '\\') {
-            ds_put_char(&s, *cp++);
+bool
+json_string_unescape(const char *in, size_t in_len, char **outp)
+{
+    const char *end = in + in_len;
+    bool ok = false;
+    struct ds out;
+
+    ds_init(&out);
+    ds_reserve(&out, in_len);
+    while (in < end) {
+        if (*in == '"') {
+            ds_clear(&out);
+            ds_put_cstr(&out, "quoted string may not include unescaped \"");
+            goto exit;
+        }
+        if (*in != '\\') {
+            ds_put_char(&out, *in++);
             continue;
         }
 
-        cp++;
-        switch (*cp++) {
+        in++;
+        if (in >= end) {
+            /* The JSON parser will never trigger this message, because its
+             * lexer will never pass in a string that ends in a single
+             * backslash, but json_string_unescape() has other callers that
+             * are not as careful.*/
+            ds_clear(&out);
+            ds_put_cstr(&out, "quoted string may not end with backslash");
+            goto exit;
+        }
+        switch (*in++) {
         case '"': case '\\': case '/':
-            ds_put_char(&s, cp[-1]);
+            ds_put_char(&out, in[-1]);
             break;
 
         case 'b':
-            ds_put_char(&s, '\b');
+            ds_put_char(&out, '\b');
             break;
 
         case 'f':
-            ds_put_char(&s, '\f');
+            ds_put_char(&out, '\f');
             break;
 
         case 'n':
-            ds_put_char(&s, '\n');
+            ds_put_char(&out, '\n');
             break;
 
         case 'r':
-            ds_put_char(&s, '\r');
+            ds_put_char(&out, '\r');
             break;
 
         case 't':
-            ds_put_char(&s, '\t');
+            ds_put_char(&out, '\t');
             break;
 
         case 'u':
-            cp = json_lex_unicode(p, cp, &s);
-            if (!cp) {
+            in = json_lex_unicode(in, end, &out);
+            if (!in) {
                 goto exit;
             }
             break;
 
         default:
-            json_error(p, "bad escape \\%c", cp[-1]);
+            ds_clear(&out);
+            ds_put_format(&out, "bad escape \\%c", in[-1]);
             goto exit;
         }
     }
+    ok = true;
+
+exit:
+    *outp = ds_cstr(&out);
+    return ok;
+}
+
+void
+json_string_escape(const char *in, struct ds *out)
+{
+    struct json json = {
+        .type = JSON_STRING,
+        .string = CONST_CAST(char *, in),
+    };
+    json_to_ds(&json, 0, out);
+}
+
+static void
+json_parser_input_string(struct json_parser *p, const char *s)
+{
+    struct json_token token;
 
     token.type = T_STRING;
-    token.u.string = ds_cstr(&s);
+    token.string = s;
     json_parser_input(p, &token);
+}
 
-exit:
-    ds_destroy(&s);
-    return;
+static void
+json_lex_string(struct json_parser *p)
+{
+    const char *raw = ds_cstr(&p->buffer);
+    if (!strchr(raw, '\\')) {
+        json_parser_input_string(p, raw);
+    } else {
+        char *cooked;
+
+        if (json_string_unescape(raw, strlen(raw), &cooked)) {
+            json_parser_input_string(p, cooked);
+        } else {
+            json_error(p, "%s", cooked);
+        }
+
+        free(cooked);
+    }
 }
 
 static bool
@@ -881,14 +970,6 @@ json_lex_input(struct json_parser *p, unsigned char c)
 {
     struct json_token token;
 
-    p->byte_number++;
-    if (c == '\n') {
-        p->column_number = 0;
-        p->line_number++;
-    } else {
-        p->column_number++;
-    }
-
     switch (p->lex_state) {
     case JSON_LEX_START:
         switch (c) {
@@ -1008,7 +1089,8 @@ json_from_file(const char *file_name)
     stream = fopen(file_name, "r");
     if (!stream) {
         return json_string_create_nocopy(
-            xasprintf("error opening \"%s\": %s", file_name, strerror(errno)));
+            xasprintf("error opening \"%s\": %s", file_name,
+                      ovs_strerror(errno)));
     }
     json = json_from_stream(stream);
     fclose(stream);
@@ -1045,7 +1127,7 @@ json_from_stream(FILE *stream)
     if (ferror(stream)) {
         json_destroy(json);
         json = json_string_create_nocopy(
-            xasprintf("error reading JSON stream: %s", strerror(errno)));
+            xasprintf("error reading JSON stream: %s", ovs_strerror(errno)));
     }
 
     return json;
@@ -1065,6 +1147,13 @@ json_parser_feed(struct json_parser *p, const char *input, size_t n)
     size_t i;
     for (i = 0; !p->done && i < n; ) {
         if (json_lex_input(p, input[i])) {
+            p->byte_number++;
+            if (input[i] == '\n') {
+                p->column_number = 0;
+                p->line_number++;
+            } else {
+                p->column_number++;
+            }
             i++;
         }
     }
@@ -1104,8 +1193,8 @@ json_parser_finish(struct json_parser *p)
     }
 
     if (!p->error) {
-        assert(p->height == 1);
-        assert(p->stack[0].json != NULL);
+        ovs_assert(p->height == 1);
+        ovs_assert(p->stack[0].json != NULL);
         json = p->stack[--p->height].json;
     } else {
         json = json_string_create_nocopy(p->error);
@@ -1143,17 +1232,16 @@ json_parser_put_value(struct json_parser *p, struct json *value)
 {
     struct json_parser_node *node = json_parser_top(p);
     if (node->json->type == JSON_OBJECT) {
-        json_object_put(node->json, p->member_name, value);
-        free(p->member_name);
+        json_object_put_nocopy(node->json, p->member_name, value);
         p->member_name = NULL;
     } else if (node->json->type == JSON_ARRAY) {
         json_array_add(node->json, value);
     } else {
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 
-static struct json_parser_node *
+static void
 json_parser_push(struct json_parser *p,
                  struct json *new_json, enum json_parse_state new_state)
 {
@@ -1172,11 +1260,10 @@ json_parser_push(struct json_parser *p,
         node = &p->stack[p->height++];
         node->json = new_json;
         p->parse_state = new_state;
-        return node;
     } else {
+        json_destroy(new_json);
         json_error(p, "input exceeds maximum nesting depth %d",
                    JSON_MAX_HEIGHT);
-        return NULL;
     }
 }
 
@@ -1220,15 +1307,15 @@ json_parse_value(struct json_parser *p, struct json_token *token,
         return;
 
     case T_INTEGER:
-        value = json_integer_create(token->u.integer);
+        value = json_integer_create(token->integer);
         break;
 
     case T_REAL:
-        value = json_real_create(token->u.real);
+        value = json_real_create(token->real);
         break;
 
     case T_STRING:
-        value = json_string_create(token->u.string);
+        value = json_string_create(token->string);
         break;
 
     case T_EOF:
@@ -1270,7 +1357,7 @@ json_parser_pop(struct json_parser *p)
         } else if (node->json->type == JSON_OBJECT) {
             p->parse_state = JSON_PARSE_OBJECT_NEXT;
         } else {
-            NOT_REACHED();
+            OVS_NOT_REACHED();
         }
     }
 }
@@ -1301,7 +1388,7 @@ json_parser_input(struct json_parser *p, struct json_token *token)
         /* Fall through. */
     case JSON_PARSE_OBJECT_NAME:
         if (token->type == T_STRING) {
-            p->member_name = xstrdup(token->u.string);
+            p->member_name = xstrdup(token->string);
             p->parse_state = JSON_PARSE_OBJECT_COLON;
         } else {
             json_error(p, "syntax error parsing object expecting string");
@@ -1363,6 +1450,7 @@ json_create(enum json_type type)
 {
     struct json *json = xmalloc(sizeof *json);
     json->type = type;
+    json->count = 1;
     return json;
 }
 
@@ -1389,17 +1477,17 @@ json_error(struct json_parser *p, const char *format, ...)
 #define SPACES_PER_LEVEL 2
 
 struct json_serializer {
-    struct ds ds;
+    struct ds *ds;
     int depth;
     int flags;
 };
 
-static void json_to_ds(const struct json *, struct json_serializer *);
-static void json_object_to_ds(const struct shash *object,
-                              struct json_serializer *);
-static void json_array_to_ds(const struct json_array *,
-                             struct json_serializer *);
-static void json_string_to_ds(const char *string, struct ds *);
+static void json_serialize(const struct json *, struct json_serializer *);
+static void json_serialize_object(const struct shash *object,
+                                  struct json_serializer *);
+static void json_serialize_array(const struct json_array *,
+                                 struct json_serializer *);
+static void json_serialize_string(const char *, struct ds *);
 
 /* Converts 'json' to a string in JSON format, encoded in UTF-8, and returns
  * that string.  The caller is responsible for freeing the returned string,
@@ -1417,19 +1505,30 @@ static void json_string_to_ds(const char *string, struct ds *);
  * object, since a bare literal does not satisfy the JSON grammar. */
 char *
 json_to_string(const struct json *json, int flags)
+{
+    struct ds ds;
+
+    ds_init(&ds);
+    json_to_ds(json, flags, &ds);
+    return ds_steal_cstr(&ds);
+}
+
+/* Same as json_to_string(), but the output is appended to 'ds'. */
+void
+json_to_ds(const struct json *json, int flags, struct ds *ds)
 {
     struct json_serializer s;
-    ds_init(&s.ds);
+
+    s.ds = ds;
     s.depth = 0;
     s.flags = flags;
-    json_to_ds(json, &s);
-    return ds_steal_cstr(&s.ds);
+    json_serialize(json, &s);
 }
 
 static void
-json_to_ds(const struct json *json, struct json_serializer *s)
+json_serialize(const struct json *json, struct json_serializer *s)
 {
-    struct ds *ds = &s->ds;
+    struct ds *ds = s->ds;
 
     switch (json->type) {
     case JSON_NULL:
@@ -1445,28 +1544,28 @@ json_to_ds(const struct json *json, struct json_serializer *s)
         break;
 
     case JSON_OBJECT:
-        json_object_to_ds(json->u.object, s);
+        json_serialize_object(json->object, s);
         break;
 
     case JSON_ARRAY:
-        json_array_to_ds(&json->u.array, s);
+        json_serialize_array(&json->array, s);
         break;
 
     case JSON_INTEGER:
-        ds_put_format(ds, "%lld", json->u.integer);
+        ds_put_format(ds, "%lld", json->integer);
         break;
 
     case JSON_REAL:
-        ds_put_format(ds, "%.*g", DBL_DIG, json->u.real);
+        ds_put_format(ds, "%.*g", DBL_DIG, json->real);
         break;
 
     case JSON_STRING:
-        json_string_to_ds(json->u.string, ds);
+        json_serialize_string(json->string, ds);
         break;
 
     case JSON_N_TYPES:
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 
@@ -1474,34 +1573,34 @@ static void
 indent_line(struct json_serializer *s)
 {
     if (s->flags & JSSF_PRETTY) {
-        ds_put_char(&s->ds, '\n');
-        ds_put_char_multiple(&s->ds, ' ', SPACES_PER_LEVEL * s->depth);
+        ds_put_char(s->ds, '\n');
+        ds_put_char_multiple(s->ds, ' ', SPACES_PER_LEVEL * s->depth);
     }
 }
 
 static void
-json_object_member_to_ds(size_t i, const struct shash_node *node,
-                         struct json_serializer *s)
+json_serialize_object_member(size_t i, const struct shash_node *node,
+                             struct json_serializer *s)
 {
-    struct ds *ds = &s->ds;
+    struct ds *ds = s->ds;
 
     if (i) {
         ds_put_char(ds, ',');
         indent_line(s);
     }
 
-    json_string_to_ds(node->name, ds);
+    json_serialize_string(node->name, ds);
     ds_put_char(ds, ':');
     if (s->flags & JSSF_PRETTY) {
         ds_put_char(ds, ' ');
     }
-    json_to_ds(node->data, s);
+    json_serialize(node->data, s);
 }
 
 static void
-json_object_to_ds(const struct shash *object, struct json_serializer *s)
+json_serialize_object(const struct shash *object, struct json_serializer *s)
 {
-    struct ds *ds = &s->ds;
+    struct ds *ds = s->ds;
 
     ds_put_char(ds, '{');
 
@@ -1515,7 +1614,7 @@ json_object_to_ds(const struct shash *object, struct json_serializer *s)
         nodes = shash_sort(object);
         n = shash_count(object);
         for (i = 0; i < n; i++) {
-            json_object_member_to_ds(i, nodes[i], s);
+            json_serialize_object_member(i, nodes[i], s);
         }
         free(nodes);
     } else {
@@ -1524,7 +1623,7 @@ json_object_to_ds(const struct shash *object, struct json_serializer *s)
 
         i = 0;
         SHASH_FOR_EACH (node, object) {
-            json_object_member_to_ds(i++, node, s);
+            json_serialize_object_member(i++, node, s);
         }
     }
 
@@ -1533,9 +1632,9 @@ json_object_to_ds(const struct shash *object, struct json_serializer *s)
 }
 
 static void
-json_array_to_ds(const struct json_array *array, struct json_serializer *s)
+json_serialize_array(const struct json_array *array, struct json_serializer *s)
 {
-    struct ds *ds = &s->ds;
+    struct ds *ds = s->ds;
     size_t i;
 
     ds_put_char(ds, '[');
@@ -1549,7 +1648,7 @@ json_array_to_ds(const struct json_array *array, struct json_serializer *s)
                 ds_put_char(ds, ',');
                 indent_line(s);
             }
-            json_to_ds(array->elems[i], s);
+            json_serialize(array->elems[i], s);
         }
     }
 
@@ -1557,49 +1656,53 @@ json_array_to_ds(const struct json_array *array, struct json_serializer *s)
     ds_put_char(ds, ']');
 }
 
+static const char *chars_escaping[256] = {
+        "\\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",
+        " ", "!", "\\\"", "#", "$", "%", "&", "'",
+        "(", ")", "*", "+", ",", "-", ".", "/",
+        "0", "1", "2", "3", "4", "5", "6", "7",
+        "8", "9", ":", ";", "<", "=", ">", "?",
+        "@", "A", "B", "C", "D", "E", "F", "G",
+        "H", "I", "J", "K", "L", "M", "N", "O",
+        "P", "Q", "R", "S", "T", "U", "V", "W",
+        "X", "Y", "Z", "[", "\\\\", "]", "^", "_",
+        "`", "a", "b", "c", "d", "e", "f", "g",
+        "h", "i", "j", "k", "l", "m", "n", "o",
+        "p", "q", "r", "s", "t", "u", "v", "w",
+        "x", "y", "z", "{", "|", "}", "~", "\x7f",
+        "\x80", "\x81", "\x82", "\x83", "\x84", "\x85", "\x86", "\x87",
+        "\x88", "\x89", "\x8a", "\x8b", "\x8c", "\x8d", "\x8e", "\x8f",
+        "\x90", "\x91", "\x92", "\x93", "\x94", "\x95", "\x96", "\x97",
+        "\x98", "\x99", "\x9a", "\x9b", "\x9c", "\x9d", "\x9e", "\x9f",
+        "\xa0", "\xa1", "\xa2", "\xa3", "\xa4", "\xa5", "\xa6", "\xa7",
+        "\xa8", "\xa9", "\xaa", "\xab", "\xac", "\xad", "\xae", "\xaf",
+        "\xb0", "\xb1", "\xb2", "\xb3", "\xb4", "\xb5", "\xb6", "\xb7",
+        "\xb8", "\xb9", "\xba", "\xbb", "\xbc", "\xbd", "\xbe", "\xbf",
+        "\xc0", "\xc1", "\xc2", "\xc3", "\xc4", "\xc5", "\xc6", "\xc7",
+        "\xc8", "\xc9", "\xca", "\xcb", "\xcc", "\xcd", "\xce", "\xcf",
+        "\xd0", "\xd1", "\xd2", "\xd3", "\xd4", "\xd5", "\xd6", "\xd7",
+        "\xd8", "\xd9", "\xda", "\xdb", "\xdc", "\xdd", "\xde", "\xdf",
+        "\xe0", "\xe1", "\xe2", "\xe3", "\xe4", "\xe5", "\xe6", "\xe7",
+        "\xe8", "\xe9", "\xea", "\xeb", "\xec", "\xed", "\xee", "\xef",
+        "\xf0", "\xf1", "\xf2", "\xf3", "\xf4", "\xf5", "\xf6", "\xf7",
+        "\xf8", "\xf9", "\xfa", "\xfb", "\xfc", "\xfd", "\xfe", "\xff"
+};
+
 static void
-json_string_to_ds(const char *string, struct ds *ds)
+json_serialize_string(const char *string, struct ds *ds)
 {
     uint8_t c;
+    uint8_t c2;
+    const char *escape;
 
     ds_put_char(ds, '"');
     while ((c = *string++) != '\0') {
-        switch (c) {
-        case '"':
-            ds_put_cstr(ds, "\\\"");
-            break;
-
-        case '\\':
-            ds_put_cstr(ds, "\\\\");
-            break;
-
-        case '\b':
-            ds_put_cstr(ds, "\\b");
-            break;
-
-        case '\f':
-            ds_put_cstr(ds, "\\f");
-            break;
-
-        case '\n':
-            ds_put_cstr(ds, "\\n");
-            break;
-
-        case '\r':
-            ds_put_cstr(ds, "\\r");
-            break;
-
-        case '\t':
-            ds_put_cstr(ds, "\\t");
-            break;
-
-        default:
-            if (c >= 32) {
-                ds_put_char(ds, c);
-            } else {
-                ds_put_format(ds, "\\u%04x", c);
-            }
-            break;
+        escape = chars_escaping[c];
+        while ((c2 = *escape++) != '\0') {
+            ds_put_char(ds, c2);
         }
     }
     ds_put_char(ds, '"');