LCOV - code coverage report
Current view: top level - samples/techempower - json.c (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 70 392 17.9 %
Date: 2023-04-18 16:19:03 Functions: 10 43 23.3 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2017 Intel Corporation
       3             :  * Copyright (c) 2020 L. A. F. Pereira <l@tia.mat.br>
       4             :  *
       5             :  * SPDX-License-Identifier: Apache-2.0
       6             :  */
       7             : 
       8             : #include <assert.h>
       9             : #include <ctype.h>
      10             : #include <errno.h>
      11             : #include <limits.h>
      12             : #include <stdbool.h>
      13             : #include <stdint.h>
      14             : #include <stdio.h>
      15             : #include <stdlib.h>
      16             : #include <string.h>
      17             : 
      18             : #include "json.h"
      19             : #include "lwan.h"
      20             : #include "int-to-str.h"
      21             : 
      22             : struct token {
      23             :     enum json_tokens type;
      24             :     char *start;
      25             :     char *end;
      26             : };
      27             : 
      28             : struct lexer {
      29             :     void *(*state)(struct lexer *lexer);
      30             :     char *start;
      31             :     char *pos;
      32             :     char *end;
      33             :     struct token token;
      34             : };
      35             : 
      36             : struct json_obj {
      37             :     struct lexer lexer;
      38             : };
      39             : 
      40             : struct json_obj_key_value {
      41             :     const char *key;
      42             :     size_t key_len;
      43             :     struct token value;
      44             : };
      45             : 
      46           0 : static bool lexer_consume(struct lexer *lexer,
      47             :                           struct token *token,
      48             :                           enum json_tokens empty_token)
      49             : {
      50           0 :     if (lexer->token.type == empty_token) {
      51           0 :         return false;
      52             :     }
      53             : 
      54           0 :     *token = lexer->token;
      55           0 :     lexer->token.type = empty_token;
      56             : 
      57           0 :     return true;
      58             : }
      59             : 
      60           0 : static bool lexer_next(struct lexer *lexer, struct token *token)
      61             : {
      62           0 :     while (lexer->state) {
      63           0 :         if (lexer_consume(lexer, token, JSON_TOK_NONE)) {
      64           0 :             return true;
      65             :         }
      66             : 
      67           0 :         lexer->state = lexer->state(lexer);
      68             :     }
      69             : 
      70           0 :     return lexer_consume(lexer, token, JSON_TOK_EOF);
      71             : }
      72             : 
      73             : static void *lexer_json(struct lexer *lexer);
      74             : 
      75           0 : static void emit(struct lexer *lexer, enum json_tokens token)
      76             : {
      77           0 :     lexer->token.type = token;
      78           0 :     lexer->token.start = lexer->start;
      79           0 :     lexer->token.end = lexer->pos;
      80           0 :     lexer->start = lexer->pos;
      81           0 : }
      82             : 
      83           0 : static void* emit_cont(struct lexer *lexer, enum json_tokens token)
      84             : {
      85           0 :     emit(lexer, token);
      86           0 :     return lexer_json;
      87             : }
      88             : 
      89           0 : static void* emit_end(struct lexer *lexer, enum json_tokens token)
      90             : {
      91           0 :     emit(lexer, token);
      92           0 :     return NULL;
      93             : }
      94             : 
      95           0 : static int next(struct lexer *lexer)
      96             : {
      97           0 :     if (lexer->pos >= lexer->end) {
      98           0 :         lexer->pos = lexer->end + 1;
      99             : 
     100           0 :         return '\0';
     101             :     }
     102             : 
     103           0 :     return *lexer->pos++;
     104             : }
     105             : 
     106           0 : static void ignore(struct lexer *lexer) { lexer->start = lexer->pos; }
     107             : 
     108           0 : static void backup(struct lexer *lexer) { lexer->pos--; }
     109             : 
     110           0 : static int peek(struct lexer *lexer)
     111             : {
     112           0 :     int chr = next(lexer);
     113             : 
     114           0 :     backup(lexer);
     115             : 
     116           0 :     return chr;
     117             : }
     118             : 
     119           0 : static void *lexer_string(struct lexer *lexer)
     120             : {
     121           0 :     ignore(lexer);
     122             : 
     123           0 :     while (true) {
     124           0 :         int chr = next(lexer);
     125             : 
     126           0 :         if (UNLIKELY(chr == '\0')) {
     127           0 :             return emit_end(lexer, JSON_TOK_ERROR);
     128             :         }
     129             : 
     130           0 :         if (chr == '\\') {
     131           0 :             switch (next(lexer)) {
     132           0 :             case '"':
     133             :             case '\\':
     134             :             case '/':
     135             :             case 'b':
     136             :             case 'f':
     137             :             case 'n':
     138             :             case 'r':
     139             :             case 't':
     140           0 :                 continue;
     141           0 :             case 'u':
     142           0 :                 if (UNLIKELY(!isxdigit(next(lexer)))) {
     143           0 :                     goto error;
     144             :                 }
     145             : 
     146           0 :                 if (UNLIKELY(!isxdigit(next(lexer)))) {
     147           0 :                     goto error;
     148             :                 }
     149             : 
     150           0 :                 if (UNLIKELY(!isxdigit(next(lexer)))) {
     151           0 :                     goto error;
     152             :                 }
     153             : 
     154           0 :                 if (UNLIKELY(!isxdigit(next(lexer)))) {
     155           0 :                     goto error;
     156             :                 }
     157             : 
     158           0 :                 break;
     159           0 :             default:
     160           0 :                 goto error;
     161             :             }
     162             :         }
     163             : 
     164           0 :         if (chr == '"') {
     165           0 :             backup(lexer);
     166           0 :             emit(lexer, JSON_TOK_STRING);
     167             : 
     168           0 :             next(lexer);
     169           0 :             ignore(lexer);
     170             : 
     171           0 :             return lexer_json;
     172             :         }
     173             :     }
     174             : 
     175           0 : error:
     176           0 :     return emit_end(lexer, JSON_TOK_ERROR);
     177             : }
     178             : 
     179           0 : static int accept_run(struct lexer *lexer, const char *run)
     180             : {
     181           0 :     for (; *run; run++) {
     182           0 :         if (UNLIKELY(next(lexer) != *run)) {
     183           0 :             return -EINVAL;
     184             :         }
     185             :     }
     186             : 
     187           0 :     return 0;
     188             : }
     189             : 
     190           0 : static void *lexer_boolean(struct lexer *lexer)
     191             : {
     192             :     /* Already matched either `t' or `f' at this point */
     193             : 
     194           0 :     switch (next(lexer)) {
     195           0 :     case 'r':
     196           0 :         if (LIKELY(!accept_run(lexer, "ue"))) {
     197           0 :             return emit_cont(lexer, JSON_TOK_TRUE);
     198             :         }
     199           0 :         break;
     200           0 :     case 'a':
     201           0 :         if (LIKELY(!accept_run(lexer, "lse"))) {
     202           0 :             return emit_cont(lexer, JSON_TOK_FALSE);
     203             :         }
     204           0 :         break;
     205             :     }
     206             : 
     207           0 :     return emit_end(lexer, JSON_TOK_ERROR);
     208             : }
     209             : 
     210           0 : static void *lexer_null(struct lexer *lexer)
     211             : {
     212           0 :     if (UNLIKELY(accept_run(lexer, "ull") < 0)) {
     213           0 :         return emit_end(lexer, JSON_TOK_ERROR);
     214             :     }
     215             : 
     216           0 :     return emit_cont(lexer, JSON_TOK_NULL);
     217             : }
     218             : 
     219           0 : static void *lexer_number(struct lexer *lexer)
     220             : {
     221           0 :     while (true) {
     222           0 :         int chr = next(lexer);
     223             : 
     224           0 :         if (isdigit(chr) || chr == '.') {
     225           0 :             continue;
     226             :         }
     227             : 
     228           0 :         backup(lexer);
     229           0 :         return emit_cont(lexer, JSON_TOK_NUMBER);
     230             :     }
     231             : }
     232             : 
     233           0 : static void *lexer_json(struct lexer *lexer)
     234             : {
     235           0 :     while (true) {
     236           0 :         int chr = next(lexer);
     237             : 
     238           0 :         switch (chr) {
     239           0 :         case '\0':
     240           0 :             return emit_end(lexer, JSON_TOK_EOF);
     241             : 
     242           0 :         case '}':
     243             :         case '{':
     244             :         case '[':
     245             :         case ']':
     246             :         case ',':
     247             :         case ':':
     248           0 :             return emit_cont(lexer, (enum json_tokens)chr);
     249             : 
     250           0 :         case '"':
     251           0 :             return lexer_string;
     252             : 
     253           0 :         case 'n':
     254           0 :             return lexer_null;
     255             : 
     256           0 :         case 't':
     257             :         case 'f':
     258           0 :             return lexer_boolean;
     259             : 
     260           0 :         case '-':
     261           0 :             if (LIKELY(isdigit(peek(lexer)))) {
     262           0 :                 return lexer_number;
     263             :             }
     264             : 
     265             :             /* fallthrough */
     266             :         default:
     267           0 :             if (isspace(chr)) {
     268           0 :                 ignore(lexer);
     269           0 :                 continue;
     270             :             }
     271             : 
     272           0 :             if (LIKELY(isdigit(chr))) {
     273           0 :                 return lexer_number;
     274             :             }
     275             : 
     276           0 :             return emit_end(lexer, JSON_TOK_ERROR);
     277             :         }
     278             :     }
     279             : }
     280             : 
     281           0 : static void lexer_init(struct lexer *lexer, char *data, size_t len)
     282             : {
     283           0 :     lexer->state = lexer_json;
     284           0 :     lexer->start = data;
     285           0 :     lexer->pos = data;
     286           0 :     lexer->end = data + len;
     287           0 :     lexer->token.type = JSON_TOK_NONE;
     288           0 : }
     289             : 
     290           0 : static int obj_init(struct json_obj *json, char *data, size_t len)
     291             : {
     292             :     struct token token;
     293             : 
     294           0 :     lexer_init(&json->lexer, data, len);
     295             : 
     296           0 :     if (UNLIKELY(!lexer_next(&json->lexer, &token))) {
     297           0 :         return -EINVAL;
     298             :     }
     299             : 
     300           0 :     if (UNLIKELY(token.type != JSON_TOK_OBJECT_START)) {
     301           0 :         return -EINVAL;
     302             :     }
     303             : 
     304           0 :     return 0;
     305             : }
     306             : 
     307           0 : static int element_token(enum json_tokens token)
     308             : {
     309           0 :     switch (token) {
     310           0 :     case JSON_TOK_OBJECT_START:
     311             :     case JSON_TOK_LIST_START:
     312             :     case JSON_TOK_STRING:
     313             :     case JSON_TOK_NUMBER:
     314             :     case JSON_TOK_TRUE:
     315             :     case JSON_TOK_FALSE:
     316           0 :         return 0;
     317           0 :     default:
     318           0 :         return -EINVAL;
     319             :     }
     320             : }
     321             : 
     322           0 : static int obj_next(struct json_obj *json, struct json_obj_key_value *kv)
     323             : {
     324             :     struct token token;
     325             : 
     326           0 :     if (UNLIKELY(!lexer_next(&json->lexer, &token))) {
     327           0 :         return -EINVAL;
     328             :     }
     329             : 
     330             :     /* Match end of object or next key */
     331           0 :     switch (token.type) {
     332           0 :     case JSON_TOK_OBJECT_END:
     333           0 :         kv->key = NULL;
     334           0 :         kv->key_len = 0;
     335           0 :         kv->value = token;
     336             : 
     337           0 :         return 0;
     338           0 :     case JSON_TOK_COMMA:
     339           0 :         if (UNLIKELY(!lexer_next(&json->lexer, &token))) {
     340           0 :             return -EINVAL;
     341             :         }
     342             : 
     343           0 :         if (UNLIKELY(token.type != JSON_TOK_STRING)) {
     344           0 :             return -EINVAL;
     345             :         }
     346             : 
     347             :         /* fallthrough */
     348             :     case JSON_TOK_STRING:
     349           0 :         kv->key = token.start;
     350           0 :         kv->key_len = (size_t)(token.end - token.start);
     351           0 :         break;
     352           0 :     default:
     353           0 :         return -EINVAL;
     354             :     }
     355             : 
     356             :     /* Match : after key */
     357           0 :     if (UNLIKELY(!lexer_next(&json->lexer, &token))) {
     358           0 :         return -EINVAL;
     359             :     }
     360             : 
     361           0 :     if (UNLIKELY(token.type != JSON_TOK_COLON)) {
     362           0 :         return -EINVAL;
     363             :     }
     364             : 
     365             :     /* Match value */
     366           0 :     if (UNLIKELY(!lexer_next(&json->lexer, &kv->value))) {
     367           0 :         return -EINVAL;
     368             :     }
     369             : 
     370           0 :     return element_token(kv->value.type);
     371             : }
     372             : 
     373           0 : static int arr_next(struct json_obj *json, struct token *value)
     374             : {
     375           0 :     if (UNLIKELY(!lexer_next(&json->lexer, value))) {
     376           0 :         return -EINVAL;
     377             :     }
     378             : 
     379           0 :     if (value->type == JSON_TOK_LIST_END) {
     380           0 :         return 0;
     381             :     }
     382             : 
     383           0 :     if (value->type == JSON_TOK_COMMA) {
     384           0 :         if (UNLIKELY(!lexer_next(&json->lexer, value))) {
     385           0 :             return -EINVAL;
     386             :         }
     387             :     }
     388             : 
     389           0 :     return element_token(value->type);
     390             : }
     391             : 
     392           0 : static int decode_num(const struct token *token, int32_t *num)
     393             : {
     394             :     /* FIXME: strtod() is not available in newlib/minimal libc,
     395             :      * so using strtol() here.
     396             :      */
     397             :     char *endptr;
     398             :     char prev_end;
     399             : 
     400           0 :     prev_end = *token->end;
     401           0 :     *token->end = '\0';
     402             : 
     403           0 :     errno = 0;
     404           0 :     long v = strtol(token->start, &endptr, 10);
     405           0 :     if ((long)(int)v != v) {
     406           0 :         return -ERANGE;
     407             :     }
     408             : 
     409           0 :     *num = (int)v;
     410             : 
     411           0 :     *token->end = prev_end;
     412             : 
     413           0 :     if (errno != 0) {
     414           0 :         return -errno;
     415             :     }
     416             : 
     417           0 :     if (endptr != token->end) {
     418           0 :         return -EINVAL;
     419             :     }
     420             : 
     421           0 :     return 0;
     422             : }
     423             : 
     424           0 : static bool equivalent_types(enum json_tokens type1, enum json_tokens type2)
     425             : {
     426           0 :     if (type1 == JSON_TOK_TRUE || type1 == JSON_TOK_FALSE) {
     427           0 :         return type2 == JSON_TOK_TRUE || type2 == JSON_TOK_FALSE;
     428             :     }
     429             : 
     430           0 :     return type1 == type2;
     431             : }
     432             : 
     433             : static int obj_parse(struct json_obj *obj,
     434             :                      const struct json_obj_descr *descr,
     435             :                      size_t descr_len,
     436             :                      void *val);
     437             : static int arr_parse(struct json_obj *obj,
     438             :                      const struct json_obj_descr *elem_descr,
     439             :                      size_t max_elements,
     440             :                      void *field,
     441             :                      void *val);
     442             : 
     443           0 : static int decode_value(struct json_obj *obj,
     444             :                         const struct json_obj_descr *descr,
     445             :                         struct token *value,
     446             :                         void *field,
     447             :                         void *val)
     448             : {
     449             : 
     450           0 :     if (!equivalent_types(value->type, descr->type)) {
     451           0 :         return -EINVAL;
     452             :     }
     453             : 
     454           0 :     switch (descr->type) {
     455           0 :     case JSON_TOK_OBJECT_START:
     456           0 :         return obj_parse(obj, descr->object.sub_descr,
     457           0 :                          descr->object.sub_descr_len, field);
     458           0 :     case JSON_TOK_LIST_START:
     459           0 :         return arr_parse(obj, descr->array.element_descr,
     460           0 :                          descr->array.n_elements, field, val);
     461           0 :     case JSON_TOK_FALSE:
     462             :     case JSON_TOK_TRUE: {
     463           0 :         bool *v = field;
     464             : 
     465           0 :         *v = value->type == JSON_TOK_TRUE;
     466             : 
     467           0 :         return 0;
     468             :     }
     469           0 :     case JSON_TOK_NUMBER: {
     470           0 :         int32_t *num = field;
     471             : 
     472           0 :         return decode_num(value, num);
     473             :     }
     474           0 :     case JSON_TOK_STRING: {
     475           0 :         char **str = field;
     476             : 
     477           0 :         *value->end = '\0';
     478           0 :         *str = value->start;
     479             : 
     480           0 :         return 0;
     481             :     }
     482           0 :     default:
     483           0 :         return -EINVAL;
     484             :     }
     485             : }
     486             : 
     487          24 : static ptrdiff_t get_elem_size(const struct json_obj_descr *descr)
     488             : {
     489          24 :     switch (descr->type) {
     490          16 :     case JSON_TOK_NUMBER:
     491          16 :         return sizeof(int32_t);
     492           0 :     case JSON_TOK_STRING:
     493           0 :         return sizeof(char *);
     494           0 :     case JSON_TOK_TRUE:
     495             :     case JSON_TOK_FALSE:
     496           0 :         return sizeof(bool);
     497           0 :     case JSON_TOK_LIST_START:
     498           0 :         return (ptrdiff_t)descr->array.n_elements *
     499           0 :                get_elem_size(descr->array.element_descr);
     500           8 :     case JSON_TOK_OBJECT_START: {
     501           8 :         ptrdiff_t total = 0;
     502             :         size_t i;
     503             : 
     504          24 :         for (i = 0; i < descr->object.sub_descr_len; i++) {
     505          16 :             ptrdiff_t s = get_elem_size(&descr->object.sub_descr[i]);
     506             : 
     507          16 :             total += (ptrdiff_t)ROUND_UP(s, descr->object.sub_descr[i].align);
     508             :         }
     509             : 
     510           8 :         return total;
     511             :     }
     512           0 :     default:
     513           0 :         return -EINVAL;
     514             :     }
     515             : }
     516             : 
     517           0 : static int arr_parse(struct json_obj *obj,
     518             :                      const struct json_obj_descr *elem_descr,
     519             :                      size_t max_elements,
     520             :                      void *field,
     521             :                      void *val)
     522             : {
     523           0 :     ptrdiff_t elem_size = get_elem_size(elem_descr);
     524           0 :     void *last_elem = (char *)field + elem_size * (ptrdiff_t)max_elements;
     525           0 :     size_t *elements = (size_t *)((char *)val + elem_descr->offset);
     526             :     struct token value;
     527             : 
     528           0 :     assert(elem_size > 0);
     529             : 
     530           0 :     *elements = 0;
     531             : 
     532           0 :     while (!arr_next(obj, &value)) {
     533           0 :         if (value.type == JSON_TOK_LIST_END) {
     534           0 :             return 0;
     535             :         }
     536             : 
     537           0 :         if (UNLIKELY(field == last_elem)) {
     538           0 :             return -ENOSPC;
     539             :         }
     540             : 
     541           0 :         if (UNLIKELY(decode_value(obj, elem_descr, &value, field, val) < 0)) {
     542           0 :             return -EINVAL;
     543             :         }
     544             : 
     545           0 :         (*elements)++;
     546           0 :         field = (char *)field + elem_size;
     547             :     }
     548             : 
     549           0 :     return -EINVAL;
     550             : }
     551             : 
     552           0 : static int obj_parse(struct json_obj *obj,
     553             :                      const struct json_obj_descr *descr,
     554             :                      size_t descr_len,
     555             :                      void *val)
     556             : {
     557             :     struct json_obj_key_value kv;
     558           0 :     int32_t decoded_fields = 0;
     559             :     size_t i;
     560             :     int ret;
     561             : 
     562           0 :     while (!obj_next(obj, &kv)) {
     563           0 :         if (kv.value.type == JSON_TOK_OBJECT_END) {
     564           0 :             return decoded_fields;
     565             :         }
     566             : 
     567           0 :         for (i = 0; i < descr_len; i++) {
     568           0 :             void *decode_field = (char *)val + descr[i].offset;
     569             : 
     570             :             /* Field has been decoded already, skip */
     571           0 :             if (decoded_fields & (1 << i)) {
     572           0 :                 continue;
     573             :             }
     574             : 
     575             :             /* Check if it's the i-th field */
     576           0 :             if (kv.key_len != descr[i].field_name_len) {
     577           0 :                 continue;
     578             :             }
     579             : 
     580           0 :             if (memcmp(kv.key, descr[i].field_name, descr[i].field_name_len)) {
     581           0 :                 continue;
     582             :             }
     583             : 
     584             :             /* Store the decoded value */
     585           0 :             ret = decode_value(obj, &descr[i], &kv.value, decode_field, val);
     586           0 :             if (UNLIKELY(UNLIKELY(ret < 0))) {
     587           0 :                 return ret;
     588             :             }
     589             : 
     590           0 :             decoded_fields |= 1 << i;
     591           0 :             break;
     592             :         }
     593             :     }
     594             : 
     595           0 :     return -EINVAL;
     596             : }
     597             : 
     598           0 : int json_obj_parse(char *payload,
     599             :                    size_t len,
     600             :                    const struct json_obj_descr *descr,
     601             :                    size_t descr_len,
     602             :                    void *val)
     603             : {
     604             :     struct json_obj obj;
     605             :     int ret;
     606             : 
     607           0 :     assert(descr_len < (sizeof(ret) * CHAR_BIT - 1));
     608             : 
     609           0 :     ret = obj_init(&obj, payload, len);
     610           0 :     if (UNLIKELY(ret < 0)) {
     611           0 :         return ret;
     612             :     }
     613             : 
     614           0 :     return obj_parse(&obj, descr, descr_len, val);
     615             : }
     616             : 
     617             : /*
     618             :  * Routines has_zero() and has_value() are from
     619             :  * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
     620             :  */
     621             : static ALWAYS_INLINE uint64_t has_zero(uint64_t v)
     622             : {
     623          13 :     return (v - 0x0101010101010101UL) & ~v & 0x8080808080808080UL;
     624             : }
     625             : 
     626             : static ALWAYS_INLINE uint64_t has_value(uint64_t x, char n)
     627             : {
     628          13 :     return has_zero(x ^ (~0UL / 255 * (uint64_t)n));
     629             : }
     630             : 
     631          13 : static char escape_as(char chr)
     632             : {
     633             :     static const char escaped[] = {'"', '\\', 'b', 'f', 'n', 'r', 't', 't'};
     634          13 :     uint64_t mask = has_value(0x225c080c0a0d0909UL, chr);
     635          13 :     return mask == 0 ? 0 : escaped[__builtin_clzl(mask) / 8];
     636             : }
     637             : 
     638           1 : static int json_escape_internal(const char *str,
     639             :                                 json_append_bytes_t append_bytes,
     640             :                                 void *data)
     641             : {
     642             :     const char *cur;
     643             :     const char *unescaped;
     644           1 :     int ret = 0;
     645             : 
     646          14 :     for (cur = unescaped = str; *cur; cur++) {
     647          13 :         char escaped = escape_as(*cur);
     648             : 
     649          13 :         if (escaped) {
     650           0 :             char bytes[2] = {'\\', escaped};
     651             : 
     652           0 :             if (cur - unescaped) {
     653           0 :                 ret |= append_bytes(unescaped, (size_t)(cur - unescaped), data);
     654           0 :                 unescaped = cur + 1;
     655             :             }
     656             : 
     657           0 :             ret |= append_bytes(bytes, 2, data);
     658             :         }
     659             :     }
     660             : 
     661           1 :     if (cur - unescaped)
     662           1 :         ret |= append_bytes(unescaped, (size_t)(cur - unescaped), data);
     663             : 
     664           1 :     return ret;
     665             : }
     666             : 
     667           0 : size_t json_calc_escaped_len(const char *str, size_t len)
     668             : {
     669           0 :     size_t escaped_len = len;
     670             :     size_t pos;
     671             : 
     672           0 :     for (pos = 0; pos < len; pos++) {
     673           0 :         if (escape_as(str[pos])) {
     674           0 :             escaped_len++;
     675             :         }
     676             :     }
     677             : 
     678           0 :     return escaped_len;
     679             : }
     680             : 
     681           0 : ssize_t json_escape(char *str, size_t *len, size_t buf_size)
     682             : {
     683             :     char *next; /* Points after next character to escape. */
     684             :     char *dest; /* Points after next place to write escaped character. */
     685           0 :     size_t escaped_len = json_calc_escaped_len(str, *len);
     686             : 
     687           0 :     if (escaped_len == *len) {
     688             :         /*
     689             :          * If no escape is necessary, there is nothing to do.
     690             :          */
     691           0 :         return 0;
     692             :     }
     693             : 
     694           0 :     if (UNLIKELY(escaped_len >= buf_size)) {
     695           0 :         return -ENOMEM;
     696             :     }
     697             : 
     698             :     /*
     699             :      * By walking backwards in the buffer from the end positions
     700             :      * of both the original and escaped strings, we avoid using
     701             :      * extra space. Characters in the original string are
     702             :      * overwritten only after they have already been escaped.
     703             :      */
     704           0 :     str[escaped_len] = '\0';
     705           0 :     for (next = &str[*len], dest = &str[escaped_len]; next != str;) {
     706           0 :         char next_c = *(--next);
     707           0 :         char escape = escape_as(next_c);
     708             : 
     709           0 :         if (escape) {
     710           0 :             *(--dest) = escape;
     711           0 :             *(--dest) = '\\';
     712             :         } else {
     713           0 :             *(--dest) = next_c;
     714             :         }
     715             :     }
     716           0 :     *len = escaped_len;
     717             : 
     718           0 :     return 0;
     719             : }
     720             : 
     721             : static int encode(const struct json_obj_descr *descr,
     722             :                   const void *val,
     723             :                   json_append_bytes_t append_bytes,
     724             :                   void *data,
     725             :                   bool escape_key);
     726             : 
     727           8 : static int arr_encode(const struct json_obj_descr *elem_descr,
     728             :                       const void *field,
     729             :                       const void *val,
     730             :                       json_append_bytes_t append_bytes,
     731             :                       void *data,
     732             :                       bool escape_key)
     733             : {
     734           8 :     ptrdiff_t elem_size = get_elem_size(elem_descr);
     735             :     /*
     736             :      * NOTE: Since an element descriptor's offset isn't meaningful (array
     737             :      * elements occur at multiple offsets in `val'), we use its space in
     738             :      * elem_descr to store the offset to the field containing the number of
     739             :      * elements.
     740             :      */
     741           8 :     size_t n_elem = *(size_t *)((char *)val + elem_descr->offset);
     742           8 :     int ret = append_bytes("[", 1, data);
     743             : 
     744           8 :     if (LIKELY(n_elem)) {
     745           8 :         n_elem--;
     746        1114 :         for (size_t i = 0; i < n_elem; i++) {
     747             :             /*
     748             :              * Though "field" points at the next element in the array which we
     749             :              * need to encode, the value in elem_descr->offset is actually the
     750             :              * offset of the length field in the "parent" struct containing the
     751             :              * array.
     752             :              *
     753             :              * To patch things up, we lie to encode() about where the field is
     754             :              * by exactly the amount it will offset it.  This is a size
     755             :              * optimization for struct json_obj_descr: the alternative is to
     756             :              * keep a separate field next to element_descr which is an offset to
     757             :              * the length field in the parent struct, but that would add a
     758             :              * size_t to every descriptor.
     759             :              */
     760        1106 :             ret |= encode(elem_descr, (char *)field - elem_descr->offset,
     761             :                           append_bytes, data, escape_key);
     762             : 
     763        1106 :             ret |= append_bytes(",", 1, data);
     764             : 
     765        1106 :             field = (char *)field + elem_size;
     766             :         }
     767             : 
     768           8 :         ret |= encode(elem_descr, (char *)field - elem_descr->offset,
     769             :                       append_bytes, data, escape_key);
     770             :     }
     771             : 
     772           8 :     return ret | append_bytes("]", 1, data);
     773             : }
     774             : 
     775           1 : static int str_encode(const char **str,
     776             :                       json_append_bytes_t append_bytes,
     777             :                       void *data)
     778             : {
     779           1 :     int ret = append_bytes("\"", 1, data);
     780             : 
     781           1 :     ret |= json_escape_internal(*str, append_bytes, data);
     782             : 
     783           1 :     return ret | append_bytes("\"", 1, data);
     784             : }
     785             : 
     786             : static int
     787        2230 : num_encode(const int32_t *num, json_append_bytes_t append_bytes, void *data)
     788             : {
     789             :     char buf[INT_TO_STR_BUFFER_SIZE];
     790             :     size_t len;
     791        2230 :     char *as_string = int_to_string(*num, buf, &len);
     792             : 
     793        2230 :     return append_bytes(as_string, len, data);
     794             : }
     795             : 
     796             : static int
     797           0 : bool_encode(const bool *value, json_append_bytes_t append_bytes, void *data)
     798             : {
     799           0 :     if (*value) {
     800           0 :         return append_bytes("true", 4, data);
     801             :     }
     802             : 
     803           0 :     return append_bytes("false", 5, data);
     804             : }
     805             : 
     806           8 : int json_arr_encode_full(const struct json_obj_descr *descr,
     807             :                          const void *val,
     808             :                          json_append_bytes_t append_bytes,
     809             :                          void *data,
     810             :                          bool escape_key)
     811             : {
     812           8 :     void *ptr = (char *)val + descr->offset;
     813             : 
     814           8 :     return arr_encode(descr->array.element_descr, ptr, val, append_bytes, data,
     815             :                       escape_key);
     816             : }
     817             : 
     818        3345 : static int encode(const struct json_obj_descr *descr,
     819             :                   const void *val,
     820             :                   json_append_bytes_t append_bytes,
     821             :                   void *data,
     822             :                   bool escape_key)
     823             : {
     824        3345 :     void *ptr = (char *)val + descr->offset;
     825             : 
     826        3345 :     switch (descr->type) {
     827           0 :     case JSON_TOK_FALSE:
     828             :     case JSON_TOK_TRUE:
     829           0 :         return bool_encode(ptr, append_bytes, data);
     830           1 :     case JSON_TOK_STRING:
     831           1 :         return str_encode(ptr, append_bytes, data);
     832           0 :     case JSON_TOK_LIST_START:
     833           0 :         return arr_encode(descr->array.element_descr, ptr, val,
     834             :                           append_bytes, data, escape_key);
     835        1114 :     case JSON_TOK_OBJECT_START:
     836        1114 :         return json_obj_encode_full(descr->object.sub_descr,
     837        1114 :                                     descr->object.sub_descr_len, ptr, append_bytes,
     838             :                                     data, escape_key);
     839        2230 :     case JSON_TOK_NUMBER:
     840        2230 :         return num_encode(ptr, append_bytes, data);
     841           0 :     default:
     842           0 :         return -EINVAL;
     843             :     }
     844             : }
     845             : 
     846        2231 : static inline int encode_key(const struct json_obj_descr *descr,
     847             :                              json_append_bytes_t append_bytes,
     848             :                              void *data,
     849             :                              bool escape_key)
     850             : {
     851             :     int ret;
     852             : 
     853        2231 :     if (!escape_key) {
     854             :         /* Keys are encoded twice in the descriptor; once without quotes and
     855             :          * the trailing comma, and one with.  Doing it like so cuts some
     856             :          * indirect calls to append_bytes(), which in turn also potentially
     857             :          * cuts some branches in most implementations of it.  */
     858        2231 :         ret = append_bytes(descr->field_name + descr->field_name_len,
     859        2231 :                            descr->field_name_len + 3 /* 3=len('"":') */, data);
     860             :     } else {
     861           0 :         ret = str_encode((const char **)&descr->field_name, append_bytes, data);
     862           0 :         ret |= append_bytes(":", 1, data);
     863             :     }
     864             : 
     865        2231 :     return ret;
     866             : }
     867             : 
     868        1116 : int json_obj_encode_full(const struct json_obj_descr *descr,
     869             :                          size_t descr_len,
     870             :                          const void *val,
     871             :                          json_append_bytes_t append_bytes,
     872             :                          void *data,
     873             :                          bool escape_key)
     874             : {
     875        1116 :     int ret = append_bytes("{", 1, data);
     876             : 
     877        1116 :     if (LIKELY(descr_len)) {
     878             :         /* To avoid checking if we're encoding the last element on each
     879             :          * iteration of this loop, start at the second descriptor, and always
     880             :          * write the comma. Then, after the loop, encode the first descriptor.
     881             :          * If the descriptor array has only 1 element, this loop won't run. This
     882             :          * is fine since order isn't important for objects, and we save some
     883             :          * branches.  */
     884             : 
     885        2231 :         for (size_t i = 1; i < descr_len; i++) {
     886        1115 :             ret |= encode_key(&descr[i], append_bytes, data, escape_key);
     887        1115 :             ret |= encode(&descr[i], val, append_bytes, data, escape_key);
     888        1115 :             ret |= append_bytes(",", 1, data);
     889             :         }
     890             : 
     891        1116 :         ret |= encode_key(&descr[0], append_bytes, data, escape_key);
     892        1116 :         ret |= encode(&descr[0], val, append_bytes, data, escape_key);
     893             :     }
     894             : 
     895        1116 :     return ret | append_bytes("}", 1, data);
     896             : }
     897             : 
     898             : struct appender {
     899             :     char *buffer;
     900             :     size_t used;
     901             :     size_t size;
     902             : };
     903             : 
     904           0 : static int append_bytes_to_buf(const char *bytes, size_t len, void *data)
     905             : {
     906           0 :     struct appender *appender = data;
     907             : 
     908           0 :     if (UNLIKELY(len > appender->size - appender->used)) {
     909           0 :         return -ENOMEM;
     910             :     }
     911             : 
     912           0 :     memcpy(appender->buffer + appender->used, bytes, len);
     913           0 :     appender->used += len;
     914           0 :     appender->buffer[appender->used] = '\0';
     915             : 
     916           0 :     return 0;
     917             : }
     918             : 
     919           0 : int json_obj_encode_buf(const struct json_obj_descr *descr,
     920             :                         size_t descr_len,
     921             :                         const void *val,
     922             :                         char *buffer,
     923             :                         size_t buf_size)
     924             : {
     925           0 :     struct appender appender = {.buffer = buffer, .size = buf_size};
     926             : 
     927           0 :     return json_obj_encode(descr, descr_len, val, append_bytes_to_buf,
     928             :                            &appender);
     929             : }
     930             : 
     931             : static int
     932           0 : measure_bytes(const char *bytes __attribute__((unused)), size_t len, void *data)
     933             : {
     934           0 :     ssize_t *total = data;
     935             : 
     936           0 :     *total += (ssize_t)len;
     937             : 
     938           0 :     return 0;
     939             : }
     940             : 
     941           0 : ssize_t json_calc_encoded_len(const struct json_obj_descr *descr,
     942             :                               size_t descr_len,
     943             :                               const void *val)
     944             : {
     945           0 :     ssize_t total = 0;
     946             :     int ret;
     947             : 
     948           0 :     ret = json_obj_encode(descr, descr_len, val, measure_bytes, &total);
     949           0 :     if (UNLIKELY(ret < 0)) {
     950           0 :         return ret;
     951             :     }
     952             : 
     953           0 :     return total;
     954             : }

Generated by: LCOV version 1.15-2-gb9d6727