LCOV - code coverage report
Current view: top level - core/json - json_string.c (source / functions) Hit Total Coverage
Test: tmp.CaZ6RjdVn2 Lines: 172 173 99.4 %
Date: 2015-12-10 22:15:08 Functions: 21 21 100.0 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  * Copyright 2015, Google Inc.
       4             :  * All rights reserved.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions are
       8             :  * met:
       9             :  *
      10             :  *     * Redistributions of source code must retain the above copyright
      11             :  * notice, this list of conditions and the following disclaimer.
      12             :  *     * Redistributions in binary form must reproduce the above
      13             :  * copyright notice, this list of conditions and the following disclaimer
      14             :  * in the documentation and/or other materials provided with the
      15             :  * distribution.
      16             :  *     * Neither the name of Google Inc. nor the names of its
      17             :  * contributors may be used to endorse or promote products derived from
      18             :  * this software without specific prior written permission.
      19             :  *
      20             :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      21             :  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      22             :  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      23             :  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
      24             :  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      25             :  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
      26             :  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      27             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      28             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      29             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      30             :  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      31             :  *
      32             :  */
      33             : 
      34             : #include <string.h>
      35             : #include <stdlib.h>
      36             : 
      37             : #include <grpc/support/alloc.h>
      38             : #include <grpc/support/log.h>
      39             : 
      40             : #include "src/core/json/json.h"
      41             : #include "src/core/json/json_reader.h"
      42             : #include "src/core/json/json_writer.h"
      43             : 
      44             : /* The json reader will construct a bunch of grpc_json objects and
      45             :  * link them all up together in a tree-like structure that will represent
      46             :  * the json data in memory.
      47             :  *
      48             :  * It also uses its own input as a scratchpad to store all of the decoded,
      49             :  * unescaped strings. So we need to keep track of all these pointers in
      50             :  * that opaque structure the reader will carry for us.
      51             :  *
      52             :  * Note that this works because the act of parsing json always reduces its
      53             :  * input size, and never expands it.
      54             :  */
      55             : typedef struct {
      56             :   grpc_json *top;
      57             :   grpc_json *current_container;
      58             :   grpc_json *current_value;
      59             :   gpr_uint8 *input;
      60             :   gpr_uint8 *key;
      61             :   gpr_uint8 *string;
      62             :   gpr_uint8 *string_ptr;
      63             :   size_t remaining_input;
      64             : } json_reader_userdata;
      65             : 
      66             : /* This json writer will put everything in a big string.
      67             :  * The point is that we allocate that string in chunks of 256 bytes.
      68             :  */
      69             : typedef struct {
      70             :   char *output;
      71             :   size_t free_space;
      72             :   size_t string_len;
      73             :   size_t allocated;
      74             : } json_writer_userdata;
      75             : 
      76             : /* This function checks if there's enough space left in the output buffer,
      77             :  * and will enlarge it if necessary. We're only allocating chunks of 256
      78             :  * bytes at a time (or multiples thereof).
      79             :  */
      80        1903 : static void json_writer_output_check(void *userdata, size_t needed) {
      81        1903 :   json_writer_userdata *state = userdata;
      82        3806 :   if (state->free_space >= needed) return;
      83          32 :   needed -= state->free_space;
      84             :   /* Round up by 256 bytes. */
      85          32 :   needed = (needed + 0xff) & ~0xffU;
      86          32 :   state->output = gpr_realloc(state->output, state->allocated + needed);
      87          32 :   state->free_space += needed;
      88          32 :   state->allocated += needed;
      89             : }
      90             : 
      91             : /* These are needed by the writer's implementation. */
      92        1851 : static void json_writer_output_char(void *userdata, char c) {
      93        1851 :   json_writer_userdata *state = userdata;
      94        1851 :   json_writer_output_check(userdata, 1);
      95        1851 :   state->output[state->string_len++] = c;
      96        1851 :   state->free_space--;
      97        1851 : }
      98             : 
      99          52 : static void json_writer_output_string_with_len(void *userdata, const char *str,
     100             :                                                size_t len) {
     101          52 :   json_writer_userdata *state = userdata;
     102          52 :   json_writer_output_check(userdata, len);
     103          52 :   memcpy(state->output + state->string_len, str, len);
     104          52 :   state->string_len += len;
     105          52 :   state->free_space -= len;
     106          52 : }
     107             : 
     108          27 : static void json_writer_output_string(void *userdata, const char *str) {
     109          27 :   size_t len = strlen(str);
     110          27 :   json_writer_output_string_with_len(userdata, str, len);
     111          27 : }
     112             : 
     113             : /* The reader asks us to clear our scratchpad. In our case, we'll simply mark
     114             :  * the end of the current string, and advance our output pointer.
     115             :  */
     116         649 : static void json_reader_string_clear(void *userdata) {
     117         649 :   json_reader_userdata *state = userdata;
     118         649 :   if (state->string) {
     119         537 :     GPR_ASSERT(state->string_ptr < state->input);
     120         537 :     *state->string_ptr++ = 0;
     121             :   }
     122         649 :   state->string = state->string_ptr;
     123         649 : }
     124             : 
     125       24968 : static void json_reader_string_add_char(void *userdata, gpr_uint32 c) {
     126       24968 :   json_reader_userdata *state = userdata;
     127       24968 :   GPR_ASSERT(state->string_ptr < state->input);
     128       24968 :   GPR_ASSERT(c <= 0xff);
     129       24968 :   *state->string_ptr++ = (gpr_uint8)c;
     130       24968 : }
     131             : 
     132             : /* We are converting a UTF-32 character into UTF-8 here,
     133             :  * as described by RFC3629.
     134             :  */
     135          11 : static void json_reader_string_add_utf32(void *userdata, gpr_uint32 c) {
     136          11 :   if (c <= 0x7f) {
     137           4 :     json_reader_string_add_char(userdata, c);
     138           7 :   } else if (c <= 0x7ff) {
     139           4 :     gpr_uint32 b1 = 0xc0 | ((c >> 6) & 0x1f);
     140           4 :     gpr_uint32 b2 = 0x80 | (c & 0x3f);
     141           4 :     json_reader_string_add_char(userdata, b1);
     142           4 :     json_reader_string_add_char(userdata, b2);
     143           3 :   } else if (c <= 0xffff) {
     144           2 :     gpr_uint32 b1 = 0xe0 | ((c >> 12) & 0x0f);
     145           2 :     gpr_uint32 b2 = 0x80 | ((c >> 6) & 0x3f);
     146           2 :     gpr_uint32 b3 = 0x80 | (c & 0x3f);
     147           2 :     json_reader_string_add_char(userdata, b1);
     148           2 :     json_reader_string_add_char(userdata, b2);
     149           2 :     json_reader_string_add_char(userdata, b3);
     150           1 :   } else if (c <= 0x1fffff) {
     151           1 :     gpr_uint32 b1 = 0xf0 | ((c >> 18) & 0x07);
     152           1 :     gpr_uint32 b2 = 0x80 | ((c >> 12) & 0x3f);
     153           1 :     gpr_uint32 b3 = 0x80 | ((c >> 6) & 0x3f);
     154           1 :     gpr_uint32 b4 = 0x80 | (c & 0x3f);
     155           1 :     json_reader_string_add_char(userdata, b1);
     156           1 :     json_reader_string_add_char(userdata, b2);
     157           1 :     json_reader_string_add_char(userdata, b3);
     158           1 :     json_reader_string_add_char(userdata, b4);
     159             :   }
     160          11 : }
     161             : 
     162             : /* We consider that the input may be a zero-terminated string. So we
     163             :  * can end up hitting eof before the end of the alleged string length.
     164             :  */
     165       27623 : static gpr_uint32 json_reader_read_char(void *userdata) {
     166             :   gpr_uint32 r;
     167       27623 :   json_reader_userdata *state = userdata;
     168             : 
     169       27623 :   if (state->remaining_input == 0) return GRPC_JSON_READ_CHAR_EOF;
     170             : 
     171       27597 :   r = *state->input++;
     172       27597 :   state->remaining_input--;
     173             : 
     174       27597 :   if (r == 0) {
     175          59 :     state->remaining_input = 0;
     176          59 :     return GRPC_JSON_READ_CHAR_EOF;
     177             :   }
     178             : 
     179       27538 :   return r;
     180             : }
     181             : 
     182             : /* Helper function to create a new grpc_json object and link it into
     183             :  * our tree-in-progress inside our opaque structure.
     184             :  */
     185         372 : static grpc_json *json_create_and_link(void *userdata, grpc_json_type type) {
     186         372 :   json_reader_userdata *state = userdata;
     187         372 :   grpc_json *json = grpc_json_create(type);
     188             : 
     189         372 :   json->parent = state->current_container;
     190         372 :   json->prev = state->current_value;
     191         372 :   state->current_value = json;
     192             : 
     193         372 :   if (json->prev) {
     194         206 :     json->prev->next = json;
     195             :   }
     196         372 :   if (json->parent) {
     197         283 :     if (!json->parent->child) {
     198          77 :       json->parent->child = json;
     199             :     }
     200         283 :     if (json->parent->type == GRPC_JSON_OBJECT) {
     201         259 :       json->key = (char *)state->key;
     202             :     }
     203             :   }
     204         372 :   if (!state->top) {
     205          89 :     state->top = json;
     206             :   }
     207             : 
     208         372 :   return json;
     209             : }
     210             : 
     211          90 : static void json_reader_container_begins(void *userdata, grpc_json_type type) {
     212          90 :   json_reader_userdata *state = userdata;
     213             :   grpc_json *container;
     214             : 
     215          90 :   GPR_ASSERT(type == GRPC_JSON_ARRAY || type == GRPC_JSON_OBJECT);
     216             : 
     217          90 :   container = json_create_and_link(userdata, type);
     218          90 :   state->current_container = container;
     219          90 :   state->current_value = NULL;
     220          90 : }
     221             : 
     222             : /* It's important to remember that the reader is mostly stateless, so it
     223             :  * isn't trying to remember what the container was prior the one that just
     224             :  * ends. Since we're keeping track of these for our own purpose, we are
     225             :  * able to return that information back, which is useful for it to validate
     226             :  * the input json stream.
     227             :  *
     228             :  * Also note that if we're at the top of the tree, and the last container
     229             :  * ends, we have to return GRPC_JSON_TOP_LEVEL.
     230             :  */
     231          80 : static grpc_json_type json_reader_container_ends(void *userdata) {
     232          80 :   grpc_json_type container_type = GRPC_JSON_TOP_LEVEL;
     233          80 :   json_reader_userdata *state = userdata;
     234             : 
     235          80 :   GPR_ASSERT(state->current_container);
     236             : 
     237          80 :   state->current_value = state->current_container;
     238          80 :   state->current_container = state->current_container->parent;
     239             : 
     240          80 :   if (state->current_container) {
     241          12 :     container_type = state->current_container->type;
     242             :   }
     243             : 
     244          80 :   return container_type;
     245             : }
     246             : 
     247             : /* The next 3 functions basically are the reader asking us to use our string
     248             :  * scratchpad for one of these 3 purposes.
     249             :  *
     250             :  * Note that in the set_number case, we're not going to try interpreting it.
     251             :  * We'll keep it as a string, and leave it to the caller to evaluate it.
     252             :  */
     253         259 : static void json_reader_set_key(void *userdata) {
     254         259 :   json_reader_userdata *state = userdata;
     255         259 :   state->key = state->string;
     256         259 : }
     257             : 
     258         236 : static void json_reader_set_string(void *userdata) {
     259         236 :   json_reader_userdata *state = userdata;
     260         236 :   grpc_json *json = json_create_and_link(userdata, GRPC_JSON_STRING);
     261         236 :   json->value = (char *)state->string;
     262         236 : }
     263             : 
     264          42 : static int json_reader_set_number(void *userdata) {
     265          42 :   json_reader_userdata *state = userdata;
     266          42 :   grpc_json *json = json_create_and_link(userdata, GRPC_JSON_NUMBER);
     267          42 :   json->value = (char *)state->string;
     268          42 :   return 1;
     269             : }
     270             : 
     271             : /* The object types true, false and null are self-sufficient, and don't need
     272             :  * any more information beside their type.
     273             :  */
     274           2 : static void json_reader_set_true(void *userdata) {
     275           2 :   json_create_and_link(userdata, GRPC_JSON_TRUE);
     276           2 : }
     277             : 
     278           1 : static void json_reader_set_false(void *userdata) {
     279           1 :   json_create_and_link(userdata, GRPC_JSON_FALSE);
     280           1 : }
     281             : 
     282           1 : static void json_reader_set_null(void *userdata) {
     283           1 :   json_create_and_link(userdata, GRPC_JSON_NULL);
     284           1 : }
     285             : 
     286             : static grpc_json_reader_vtable reader_vtable = {
     287             :     json_reader_string_clear,     json_reader_string_add_char,
     288             :     json_reader_string_add_utf32, json_reader_read_char,
     289             :     json_reader_container_begins, json_reader_container_ends,
     290             :     json_reader_set_key,          json_reader_set_string,
     291             :     json_reader_set_number,       json_reader_set_true,
     292             :     json_reader_set_false,        json_reader_set_null};
     293             : 
     294             : /* And finally, let's define our public API. */
     295         113 : grpc_json *grpc_json_parse_string_with_len(char *input, size_t size) {
     296             :   grpc_json_reader reader;
     297             :   json_reader_userdata state;
     298         113 :   grpc_json *json = NULL;
     299             :   grpc_json_reader_status status;
     300             : 
     301         113 :   if (!input) return NULL;
     302             : 
     303         112 :   state.top = state.current_container = state.current_value = NULL;
     304         112 :   state.string = state.key = NULL;
     305         112 :   state.string_ptr = state.input = (gpr_uint8 *)input;
     306         112 :   state.remaining_input = size;
     307         112 :   grpc_json_reader_init(&reader, &reader_vtable, &state);
     308             : 
     309         112 :   status = grpc_json_reader_run(&reader);
     310         112 :   json = state.top;
     311             : 
     312         112 :   if ((status != GRPC_JSON_DONE) && json) {
     313          13 :     grpc_json_destroy(json);
     314          13 :     json = NULL;
     315             :   }
     316             : 
     317         112 :   return json;
     318             : }
     319             : 
     320             : #define UNBOUND_JSON_STRING_LENGTH 0x7fffffff
     321             : 
     322          87 : grpc_json *grpc_json_parse_string(char *input) {
     323          87 :   return grpc_json_parse_string_with_len(input, UNBOUND_JSON_STRING_LENGTH);
     324             : }
     325             : 
     326          53 : static void json_dump_recursive(grpc_json_writer *writer, grpc_json *json,
     327             :                                 int in_object) {
     328         217 :   while (json) {
     329         111 :     if (in_object) grpc_json_writer_object_key(writer, json->key);
     330             : 
     331         111 :     switch (json->type) {
     332             :       case GRPC_JSON_OBJECT:
     333             :       case GRPC_JSON_ARRAY:
     334          24 :         grpc_json_writer_container_begins(writer, json->type);
     335          24 :         if (json->child)
     336          21 :           json_dump_recursive(writer, json->child,
     337          21 :                               json->type == GRPC_JSON_OBJECT);
     338          24 :         grpc_json_writer_container_ends(writer, json->type);
     339          24 :         break;
     340             :       case GRPC_JSON_STRING:
     341          56 :         grpc_json_writer_value_string(writer, json->value);
     342          56 :         break;
     343             :       case GRPC_JSON_NUMBER:
     344          27 :         grpc_json_writer_value_raw(writer, json->value);
     345          27 :         break;
     346             :       case GRPC_JSON_TRUE:
     347           2 :         grpc_json_writer_value_raw_with_len(writer, "true", 4);
     348           2 :         break;
     349             :       case GRPC_JSON_FALSE:
     350           1 :         grpc_json_writer_value_raw_with_len(writer, "false", 5);
     351           1 :         break;
     352             :       case GRPC_JSON_NULL:
     353           1 :         grpc_json_writer_value_raw_with_len(writer, "null", 4);
     354           1 :         break;
     355             :       default:
     356           0 :         abort();
     357             :     }
     358         111 :     json = json->next;
     359             :   }
     360          53 : }
     361             : 
     362             : static grpc_json_writer_vtable writer_vtable = {
     363             :     json_writer_output_char, json_writer_output_string,
     364             :     json_writer_output_string_with_len};
     365             : 
     366          32 : char *grpc_json_dump_to_string(grpc_json *json, int indent) {
     367             :   grpc_json_writer writer;
     368             :   json_writer_userdata state;
     369             : 
     370          32 :   state.output = NULL;
     371          32 :   state.free_space = state.string_len = state.allocated = 0;
     372          32 :   grpc_json_writer_init(&writer, indent, &writer_vtable, &state);
     373             : 
     374          32 :   json_dump_recursive(&writer, json, 0);
     375             : 
     376          32 :   json_writer_output_char(&state, 0);
     377             : 
     378          32 :   return state.output;
     379             : }

Generated by: LCOV version 1.11