X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fjson.c;h=06a9a424ae2119ca738de2fa412891e4ed338389;hb=3f0cbe2df696701ad07f61add08692a1eca54f67;hp=8fd9c3a7a5e488397bbc5ac0885373eda02ec367;hpb=02dd3123a0e312f1d33403e744af52dd6096f12d;p=sliver-openvswitch.git diff --git a/lib/json.c b/lib/json.c index 8fd9c3a7a..06a9a424a 100644 --- a/lib/json.c +++ b/lib/json.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010 Nicira Networks. + * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,12 +18,10 @@ #include "json.h" -#include #include #include #include #include -#include #include #include "dynamic-string.h" @@ -277,7 +275,7 @@ json_real_create(double real) 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->u.object, name, value)); } void @@ -289,42 +287,42 @@ json_object_put_string(struct json *json, const char *name, const char *value) const char * json_string(const struct json *json) { - assert(json->type == JSON_STRING); + ovs_assert(json->type == JSON_STRING); return json->u.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->u.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->u.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); + ovs_assert(json->type == JSON_REAL || json->type == JSON_INTEGER); return json->type == JSON_REAL ? json->u.real : json->u.integer; } int64_t json_integer(const struct json *json) { - assert(json->type == JSON_INTEGER); + ovs_assert(json->type == JSON_INTEGER); return json->u.integer; } @@ -607,7 +605,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,7 +618,6 @@ 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)) { @@ -632,7 +628,6 @@ json_lex_number(struct json_parser *p) do { if (significand <= ULLONG_MAX / 10) { significand = significand * 10 + (*cp - '0'); - sig_digits++; } else { pow10++; if (*cp != '0') { @@ -656,7 +651,6 @@ json_lex_number(struct json_parser *p) do { if (significand <= ULLONG_MAX / 10) { significand = significand * 10 + (*cp - '0'); - sig_digits++; pow10--; } else if (*cp != '0') { imprecise = true; @@ -709,7 +703,6 @@ 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; json_parser_input(p, &token); @@ -719,12 +712,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 @@ -753,19 +744,15 @@ json_lex_number(struct json_parser *p) static const char * json_lex_4hex(const char *cp, const char *end, int *valuep) { - int value, i; + unsigned int value; if (cp + 4 > end) { return "quoted string ends within \\u escape"; } - value = 0; - for (i = 0; i < 4; i++) { - unsigned char c = *cp++; - if (!isxdigit(c)) { - return "malformed \\u escape"; - } - value = (value << 4) | hexit_value(c); + value = hexits_value(cp, 4, NULL); + if (value == UINT_MAX) { + return "malformed \\u escape"; } if (!value) { return "null bytes not supported in quoted strings"; @@ -832,7 +819,7 @@ json_string_unescape(const char *in, size_t in_len, char **outp) while (in < end) { if (*in == '"') { ds_clear(&out); - ds_put_cstr(&out, "quoted string may not include unescape \""); + ds_put_cstr(&out, "quoted string may not include unescaped \""); goto exit; } if (*in != '\\') { @@ -920,14 +907,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) { @@ -1104,6 +1083,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++; } } @@ -1143,8 +1129,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); @@ -1192,7 +1178,7 @@ json_parser_put_value(struct json_parser *p, struct json *value) } } -static struct json_parser_node * +static void json_parser_push(struct json_parser *p, struct json *new_json, enum json_parse_state new_state) { @@ -1211,12 +1197,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; } } @@ -1655,3 +1639,116 @@ json_serialize_string(const char *string, struct ds *ds) } ds_put_char(ds, '"'); } + +static size_t +json_string_serialized_length(const char *string) +{ + size_t length; + uint8_t c; + + length = strlen("\"\""); + + while ((c = *string++) != '\0') { + switch (c) { + case '"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + length += 2; + break; + + default: + if (c >= 32) { + length++; + } else { + /* \uXXXX */ + length += 6; + } + break; + } + } + + return length; +} + +static size_t +json_object_serialized_length(const struct shash *object) +{ + size_t length = strlen("{}"); + + if (!shash_is_empty(object)) { + struct shash_node *node; + + /* Commas and colons. */ + length += 2 * shash_count(object) - 1; + + SHASH_FOR_EACH (node, object) { + const struct json *value = node->data; + + length += json_string_serialized_length(node->name); + length += json_serialized_length(value); + } + } + + return length; +} + +static size_t +json_array_serialized_length(const struct json_array *array) +{ + size_t length = strlen("[]"); + + if (array->n) { + size_t i; + + /* Commas. */ + length += array->n - 1; + + for (i = 0; i < array->n; i++) { + length += json_serialized_length(array->elems[i]); + } + } + + return length; +} + +/* Returns strlen(json_to_string(json, 0)), that is, the number of bytes in the + * JSON output by json_to_string() for 'json' when JSSF_PRETTY is not + * requested. (JSSF_SORT does not affect the length of json_to_string()'s + * output.) */ +size_t +json_serialized_length(const struct json *json) +{ + switch (json->type) { + case JSON_NULL: + return strlen("null"); + + case JSON_FALSE: + return strlen("false"); + + case JSON_TRUE: + return strlen("true"); + + case JSON_OBJECT: + return json_object_serialized_length(json->u.object); + + case JSON_ARRAY: + return json_array_serialized_length(&json->u.array); + + case JSON_INTEGER: + return snprintf(NULL, 0, "%lld", json->u.integer); + + case JSON_REAL: + return snprintf(NULL, 0, "%.*g", DBL_DIG, json->u.real); + + case JSON_STRING: + return json_string_serialized_length(json->u.string); + + case JSON_N_TYPES: + default: + NOT_REACHED(); + } +}