LCOV - code coverage report
Current view: top level - core/json - json_writer.c (source / functions) Hit Total Coverage
Test: tmp.CaZ6RjdVn2 Lines: 133 139 95.7 %
Date: 2015-12-10 22:15:08 Functions: 14 14 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             : 
      36             : #include <grpc/support/port_platform.h>
      37             : 
      38             : #include "src/core/json/json_writer.h"
      39             : 
      40       20829 : static void json_writer_output_char(grpc_json_writer *writer, char c) {
      41       20829 :   writer->vtable->output_char(writer->userdata, c);
      42       20829 : }
      43             : 
      44          27 : static void json_writer_output_string(grpc_json_writer *writer,
      45             :                                       const char *str) {
      46          27 :   writer->vtable->output_string(writer->userdata, str);
      47          27 : }
      48             : 
      49         729 : static void json_writer_output_string_with_len(grpc_json_writer *writer,
      50             :                                                const char *str, size_t len) {
      51         729 :   writer->vtable->output_string_with_len(writer->userdata, str, len);
      52         729 : }
      53             : 
      54          36 : void grpc_json_writer_init(grpc_json_writer *writer, int indent,
      55             :                            grpc_json_writer_vtable *vtable, void *userdata) {
      56          36 :   memset(writer, 0, sizeof(*writer));
      57          36 :   writer->container_empty = 1;
      58          36 :   writer->indent = indent;
      59          36 :   writer->vtable = vtable;
      60          36 :   writer->userdata = userdata;
      61          36 : }
      62             : 
      63        1998 : static void json_writer_output_indent(grpc_json_writer *writer) {
      64             :   static const char spacesstr[] =
      65             :       "                "
      66             :       "                "
      67             :       "                "
      68             :       "                ";
      69             : 
      70        1998 :   unsigned spaces = (unsigned)(writer->depth * writer->indent);
      71             : 
      72        1998 :   if (writer->indent == 0) return;
      73             : 
      74         900 :   if (writer->got_key) {
      75         356 :     json_writer_output_char(writer, ' ');
      76         356 :     return;
      77             :   }
      78             : 
      79        1088 :   while (spaces >= (sizeof(spacesstr) - 1)) {
      80           0 :     json_writer_output_string_with_len(writer, spacesstr,
      81             :                                        sizeof(spacesstr) - 1);
      82           0 :     spaces -= (unsigned)(sizeof(spacesstr) - 1);
      83             :   }
      84             : 
      85         544 :   if (spaces == 0) return;
      86             : 
      87        1080 :   json_writer_output_string_with_len(
      88         540 :       writer, spacesstr + sizeof(spacesstr) - 1 - spaces, spaces);
      89             : }
      90             : 
      91         967 : static void json_writer_value_end(grpc_json_writer *writer) {
      92         967 :   if (writer->container_empty) {
      93         289 :     writer->container_empty = 0;
      94         289 :     if ((writer->indent == 0) || (writer->depth == 0)) return;
      95         116 :     json_writer_output_char(writer, '\n');
      96             :   } else {
      97         678 :     json_writer_output_char(writer, ',');
      98         678 :     if (writer->indent == 0) return;
      99         310 :     json_writer_output_char(writer, '\n');
     100             :   }
     101             : }
     102             : 
     103          50 : static void json_writer_escape_utf16(grpc_json_writer *writer,
     104             :                                      gpr_uint16 utf16) {
     105             :   static const char hex[] = "0123456789abcdef";
     106             : 
     107          50 :   json_writer_output_string_with_len(writer, "\\u", 2);
     108          50 :   json_writer_output_char(writer, hex[(utf16 >> 12) & 0x0f]);
     109          50 :   json_writer_output_char(writer, hex[(utf16 >> 8) & 0x0f]);
     110          50 :   json_writer_output_char(writer, hex[(utf16 >> 4) & 0x0f]);
     111          50 :   json_writer_output_char(writer, hex[(utf16)&0x0f]);
     112          50 : }
     113             : 
     114        1318 : static void json_writer_escape_string(grpc_json_writer *writer,
     115             :                                       const char *string) {
     116        1318 :   json_writer_output_char(writer, '"');
     117             : 
     118             :   for (;;) {
     119       16470 :     gpr_uint8 c = (gpr_uint8)*string++;
     120       16470 :     if (c == 0) {
     121        1316 :       break;
     122       15154 :     } else if ((c >= 32) && (c <= 126)) {
     123       15101 :       if ((c == '\\') || (c == '"')) json_writer_output_char(writer, '\\');
     124       15101 :       json_writer_output_char(writer, (char)c);
     125          53 :     } else if ((c < 32) || (c == 127)) {
     126           9 :       switch (c) {
     127             :         case '\b':
     128           0 :           json_writer_output_string_with_len(writer, "\\b", 2);
     129           0 :           break;
     130             :         case '\f':
     131           0 :           json_writer_output_string_with_len(writer, "\\f", 2);
     132           0 :           break;
     133             :         case '\n':
     134           2 :           json_writer_output_string_with_len(writer, "\\n", 2);
     135           2 :           break;
     136             :         case '\r':
     137           1 :           json_writer_output_string_with_len(writer, "\\r", 2);
     138           1 :           break;
     139             :         case '\t':
     140           4 :           json_writer_output_string_with_len(writer, "\\t", 2);
     141           4 :           break;
     142             :         default:
     143           2 :           json_writer_escape_utf16(writer, c);
     144           2 :           break;
     145             :       }
     146           9 :     } else {
     147          44 :       gpr_uint32 utf32 = 0;
     148          44 :       int extra = 0;
     149             :       int i;
     150          44 :       int valid = 1;
     151          44 :       if ((c & 0xe0) == 0xc0) {
     152          28 :         utf32 = c & 0x1f;
     153          28 :         extra = 1;
     154          16 :       } else if ((c & 0xf0) == 0xe0) {
     155           8 :         utf32 = c & 0x0f;
     156           8 :         extra = 2;
     157           8 :       } else if ((c & 0xf8) == 0xf0) {
     158           7 :         utf32 = c & 0x07;
     159           7 :         extra = 3;
     160             :       } else {
     161           1 :         break;
     162             :       }
     163         106 :       for (i = 0; i < extra; i++) {
     164          64 :         utf32 <<= 6;
     165          64 :         c = (gpr_uint8)(*string++);
     166             :         /* Breaks out and bail on any invalid UTF-8 sequence, including \0. */
     167          64 :         if ((c & 0xc0) != 0x80) {
     168           1 :           valid = 0;
     169           1 :           break;
     170             :         }
     171          63 :         utf32 |= c & 0x3f;
     172             :       }
     173          43 :       if (!valid) break;
     174             :       /* The range 0xd800 - 0xdfff is reserved by the surrogates ad vitam.
     175             :        * Any other range is technically reserved for future usage, so if we
     176             :        * don't want the software to break in the future, we have to allow
     177             :        * anything else. The first non-unicode character is 0x110000. */
     178          42 :       if (((utf32 >= 0xd800) && (utf32 <= 0xdfff)) || (utf32 >= 0x110000))
     179             :         break;
     180          42 :       if (utf32 >= 0x10000) {
     181             :         /* If utf32 contains a character that is above 0xffff, it needs to be
     182             :          * broken down into a utf-16 surrogate pair. A surrogate pair is first
     183             :          * a high surrogate, followed by a low surrogate. Each surrogate holds
     184             :          * 10 bits of usable data, thus allowing a total of 20 bits of data.
     185             :          * The high surrogate marker is 0xd800, while the low surrogate marker
     186             :          * is 0xdc00. The low 10 bits of each will be the usable data.
     187             :          *
     188             :          * After re-combining the 20 bits of data, one has to add 0x10000 to
     189             :          * the resulting value, in order to obtain the original character.
     190             :          * This is obviously because the range 0x0000 - 0xffff can be written
     191             :          * without any special trick.
     192             :          *
     193             :          * Since 0x10ffff is the highest allowed character, we're working in
     194             :          * the range 0x00000 - 0xfffff after we decrement it by 0x10000.
     195             :          * That range is exactly 20 bits.
     196             :          */
     197           6 :         utf32 -= 0x10000;
     198           6 :         json_writer_escape_utf16(writer, (gpr_uint16)(0xd800 | (utf32 >> 10)));
     199           6 :         json_writer_escape_utf16(writer,
     200           6 :                                  (gpr_uint16)(0xdc00 | (utf32 & 0x3ff)));
     201             :       } else {
     202          36 :         json_writer_escape_utf16(writer, (gpr_uint16)utf32);
     203             :       }
     204             :     }
     205       15152 :   }
     206             : 
     207        1318 :   json_writer_output_char(writer, '"');
     208        1318 : }
     209             : 
     210         268 : void grpc_json_writer_container_begins(grpc_json_writer *writer,
     211             :                                        grpc_json_type type) {
     212         268 :   if (!writer->got_key) json_writer_value_end(writer);
     213         268 :   json_writer_output_indent(writer);
     214         268 :   json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '{' : '[');
     215         268 :   writer->container_empty = 1;
     216         268 :   writer->got_key = 0;
     217         268 :   writer->depth++;
     218         268 : }
     219             : 
     220         268 : void grpc_json_writer_container_ends(grpc_json_writer *writer,
     221             :                                      grpc_json_type type) {
     222         268 :   if (writer->indent && !writer->container_empty)
     223         116 :     json_writer_output_char(writer, '\n');
     224         268 :   writer->depth--;
     225         268 :   if (!writer->container_empty) json_writer_output_indent(writer);
     226         268 :   json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '}' : ']');
     227         268 :   writer->container_empty = 0;
     228         268 :   writer->got_key = 0;
     229         268 : }
     230             : 
     231         778 : void grpc_json_writer_object_key(grpc_json_writer *writer, const char *string) {
     232         778 :   json_writer_value_end(writer);
     233         778 :   json_writer_output_indent(writer);
     234         778 :   json_writer_escape_string(writer, string);
     235         778 :   json_writer_output_char(writer, ':');
     236         778 :   writer->got_key = 1;
     237         778 : }
     238             : 
     239          27 : void grpc_json_writer_value_raw(grpc_json_writer *writer, const char *string) {
     240          27 :   if (!writer->got_key) json_writer_value_end(writer);
     241          27 :   json_writer_output_indent(writer);
     242          27 :   json_writer_output_string(writer, string);
     243          27 :   writer->got_key = 0;
     244          27 : }
     245             : 
     246         132 : void grpc_json_writer_value_raw_with_len(grpc_json_writer *writer,
     247             :                                          const char *string, size_t len) {
     248         132 :   if (!writer->got_key) json_writer_value_end(writer);
     249         132 :   json_writer_output_indent(writer);
     250         132 :   json_writer_output_string_with_len(writer, string, len);
     251         132 :   writer->got_key = 0;
     252         132 : }
     253             : 
     254         540 : void grpc_json_writer_value_string(grpc_json_writer *writer,
     255             :                                    const char *string) {
     256         540 :   if (!writer->got_key) json_writer_value_end(writer);
     257         540 :   json_writer_output_indent(writer);
     258         540 :   json_writer_escape_string(writer, string);
     259         540 :   writer->got_key = 0;
     260         540 : }

Generated by: LCOV version 1.11