LCOV - code coverage report
Current view: top level - src/json - json_encode.c (source / functions) Coverage Total Hit
Test: lcov.info Lines: 100.0 % 301 301
Test Date: 2026-03-09 04:08:32 Functions: 100.0 % 12 12
Branches: 84.8 % 244 207

             Branch data     Line data    Source code
       1                 :             : /**
       2                 :             :  * @file json_encode.c
       3                 :             :  * @brief Encode a JSON string into a compressed .trp buffer.
       4                 :             :  *
       5                 :             :  * Minimal recursive-descent parser that flattens JSON into dot-path keys.
       6                 :             :  * Objects: {"a":{"b":1}} -> key "a.b", value int(1)
       7                 :             :  * Arrays:  {"x":[10,20]} -> keys "x[0]", "x[1]"
       8                 :             :  *
       9                 :             :  * Copyright (c) 2026 M. A. Chatterjee <deftio at deftio dot com>
      10                 :             :  * BSD-2-Clause — see LICENSE.txt
      11                 :             :  */
      12                 :             : 
      13                 :             : #include "json_internal.h"
      14                 :             : 
      15                 :             : #include <ctype.h>
      16                 :             : #include <math.h>
      17                 :             : #include <stdio.h>
      18                 :             : #include <stdlib.h>
      19                 :             : #include <string.h>
      20                 :             : 
      21                 :             : /* ── Parser state ────────────────────────────────────────────────────── */
      22                 :             : 
      23                 :             : typedef struct {
      24                 :             :     const char *src;
      25                 :             :     size_t len;
      26                 :             :     size_t pos;
      27                 :             :     int depth;
      28                 :             :     tp_encoder *enc;
      29                 :             :     char path[4096]; /* current dot-path buffer */
      30                 :             :     size_t path_len;
      31                 :             : } json_parser;
      32                 :             : 
      33                 :             : /* ── Whitespace / peek helpers ───────────────────────────────────────── */
      34                 :             : 
      35                 :        2037 : static void skip_ws(json_parser *p)
      36                 :             : {
      37         [ +  + ]:        2051 :     while (p->pos < p->len) {
      38                 :        2042 :         char c = p->src[p->pos];
      39   [ +  +  +  -  :        2042 :         if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
             +  -  -  + ]
      40                 :          14 :             p->pos++;
      41                 :             :         else
      42                 :             :             break;
      43                 :             :     }
      44                 :        2037 : }
      45                 :             : 
      46                 :         420 : static char peek(json_parser *p)
      47                 :             : {
      48                 :         420 :     skip_ws(p);
      49         [ +  + ]:         420 :     if (p->pos >= p->len)
      50                 :           2 :         return '\0';
      51                 :         418 :     return p->src[p->pos];
      52                 :             : }
      53                 :             : 
      54                 :         784 : static bool expect(json_parser *p, char c)
      55                 :             : {
      56                 :         784 :     skip_ws(p);
      57   [ +  +  +  + ]:         784 :     if (p->pos < p->len && p->src[p->pos] == c) {
      58                 :         780 :         p->pos++;
      59                 :         780 :         return true;
      60                 :             :     }
      61                 :           4 :     return false;
      62                 :             : }
      63                 :             : 
      64                 :             : /* ── Path manipulation ───────────────────────────────────────────────── */
      65                 :             : 
      66                 :         206 : static void path_push_key(json_parser *p, const char *key, size_t key_len, size_t *saved_len)
      67                 :             : {
      68                 :         206 :     *saved_len = p->path_len;
      69         [ +  + ]:         206 :     if (p->path_len > 0) {
      70                 :          72 :         p->path[p->path_len++] = '.';
      71                 :             :     }
      72         [ +  - ]:         206 :     if (p->path_len + key_len < sizeof(p->path)) {
      73                 :         206 :         memcpy(p->path + p->path_len, key, key_len);
      74                 :         206 :         p->path_len += key_len;
      75                 :             :     }
      76                 :         206 :     p->path[p->path_len] = '\0';
      77                 :         206 : }
      78                 :             : 
      79                 :         100 : static void path_push_index(json_parser *p, uint32_t idx, size_t *saved_len)
      80                 :             : {
      81                 :         100 :     *saved_len = p->path_len;
      82                 :             :     char tmp[16];
      83                 :         100 :     int n = snprintf(tmp, sizeof(tmp), "[%u]", (unsigned)idx);
      84   [ +  -  +  - ]:         100 :     if (n > 0 && p->path_len + (size_t)n < sizeof(p->path)) {
      85                 :         100 :         memcpy(p->path + p->path_len, tmp, (size_t)n);
      86                 :         100 :         p->path_len += (size_t)n;
      87                 :             :     }
      88                 :         100 :     p->path[p->path_len] = '\0';
      89                 :         100 : }
      90                 :             : 
      91                 :         227 : static void path_restore(json_parser *p, size_t saved_len)
      92                 :             : {
      93                 :         227 :     p->path_len = saved_len;
      94                 :         227 :     p->path[p->path_len] = '\0';
      95                 :         227 : }
      96                 :             : 
      97                 :             : /* ── Forward declaration ─────────────────────────────────────────────── */
      98                 :             : 
      99                 :             : static tp_result parse_value(json_parser *p);
     100                 :             : 
     101                 :             : /* ── String parsing ──────────────────────────────────────────────────── */
     102                 :             : 
     103                 :         261 : static tp_result parse_string_into(json_parser *p, char *out, size_t out_cap, size_t *out_len)
     104                 :             : {
     105         [ +  + ]:         261 :     if (!expect(p, '"'))
     106                 :           1 :         return TP_ERR_JSON_SYNTAX;
     107                 :             : 
     108                 :         260 :     size_t w = 0;
     109         [ +  + ]:        1193 :     while (p->pos < p->len) {
     110                 :        1192 :         char c = p->src[p->pos++];
     111         [ +  + ]:        1192 :         if (c == '"') {
     112   [ +  -  +  - ]:         251 :             if (out && w < out_cap)
     113                 :         251 :                 out[w] = '\0';
     114                 :         251 :             *out_len = w;
     115                 :         251 :             return TP_OK;
     116                 :             :         }
     117         [ +  + ]:         941 :         if (c == '\\') {
     118         [ +  + ]:          29 :             if (p->pos >= p->len)
     119                 :           1 :                 return TP_ERR_JSON_SYNTAX;
     120                 :          28 :             char esc = p->src[p->pos++];
     121   [ +  +  +  +  :          28 :             switch (esc) {
             +  +  +  + ]
     122                 :           4 :             case '"':
     123                 :             :             case '\\':
     124                 :             :             case '/':
     125                 :           4 :                 c = esc;
     126                 :           4 :                 break;
     127                 :           2 :             case 'b':
     128                 :           2 :                 c = '\b';
     129                 :           2 :                 break;
     130                 :           2 :             case 'f':
     131                 :           2 :                 c = '\f';
     132                 :           2 :                 break;
     133                 :           2 :             case 'n':
     134                 :           2 :                 c = '\n';
     135                 :           2 :                 break;
     136                 :           2 :             case 'r':
     137                 :           2 :                 c = '\r';
     138                 :           2 :                 break;
     139                 :           2 :             case 't':
     140                 :           2 :                 c = '\t';
     141                 :           2 :                 break;
     142                 :          20 :             case 'u': {
     143                 :             :                 /* Parse 4 hex digits -> UTF-8 */
     144         [ +  + ]:          13 :                 if (p->pos + 4 > p->len)
     145                 :           1 :                     return TP_ERR_JSON_SYNTAX;
     146                 :          12 :                 uint32_t cp = 0;
     147         [ +  + ]:          56 :                 for (int i = 0; i < 4; i++) {
     148                 :          46 :                     char h = p->src[p->pos++];
     149                 :          46 :                     cp <<= 4;
     150   [ +  +  +  + ]:          46 :                     if (h >= '0' && h <= '9')
     151                 :          32 :                         cp |= (uint32_t)(h - '0');
     152   [ +  +  +  + ]:          14 :                     else if (h >= 'a' && h <= 'f')
     153                 :           4 :                         cp |= (uint32_t)(h - 'a' + 10);
     154   [ +  +  +  + ]:          10 :                     else if (h >= 'A' && h <= 'F')
     155                 :           8 :                         cp |= (uint32_t)(h - 'A' + 10);
     156                 :             :                     else
     157                 :           2 :                         return TP_ERR_JSON_SYNTAX;
     158                 :             :                 }
     159                 :             :                 /* Handle surrogate pairs */
     160   [ +  +  +  - ]:          10 :                 if (cp >= 0xD800 && cp <= 0xDBFF) {
     161   [ +  +  +  -  :           5 :                     if (p->pos + 6 > p->len || p->src[p->pos] != '\\' || p->src[p->pos + 1] != 'u')
                   -  + ]
     162                 :           1 :                         return TP_ERR_JSON_SYNTAX;
     163                 :           4 :                     p->pos += 2;
     164                 :           4 :                     uint32_t lo = 0;
     165         [ +  + ]:          17 :                     for (int i = 0; i < 4; i++) {
     166                 :          14 :                         char h = p->src[p->pos++];
     167                 :          14 :                         lo <<= 4;
     168   [ +  -  +  + ]:          14 :                         if (h >= '0' && h <= '9')
     169                 :           8 :                             lo |= (uint32_t)(h - '0');
     170   [ +  +  +  + ]:           6 :                         else if (h >= 'a' && h <= 'f')
     171                 :           2 :                             lo |= (uint32_t)(h - 'a' + 10);
     172   [ +  -  +  + ]:           4 :                         else if (h >= 'A' && h <= 'F')
     173                 :           3 :                             lo |= (uint32_t)(h - 'A' + 10);
     174                 :             :                         else
     175                 :           1 :                             return TP_ERR_JSON_SYNTAX;
     176                 :             :                     }
     177   [ +  +  -  + ]:           3 :                     if (lo < 0xDC00 || lo > 0xDFFF)
     178                 :           1 :                         return TP_ERR_JSON_SYNTAX;
     179                 :           2 :                     cp = 0x10000 + ((cp - 0xD800) << 10) + (lo - 0xDC00);
     180                 :             :                 }
     181                 :             :                 /* Encode codepoint as UTF-8 */
     182         [ +  + ]:           7 :                 if (cp < 0x80) {
     183   [ +  -  +  - ]:           1 :                     if (out && w < out_cap)
     184                 :           1 :                         out[w] = (char)cp;
     185                 :           1 :                     w++;
     186         [ +  + ]:           6 :                 } else if (cp < 0x800) {
     187   [ +  -  +  - ]:           3 :                     if (out && w + 1 < out_cap) {
     188                 :           3 :                         out[w] = (char)(0xC0 | (cp >> 6));
     189                 :           3 :                         out[w + 1] = (char)(0x80 | (cp & 0x3F));
     190                 :             :                     }
     191                 :           3 :                     w += 2;
     192         [ +  + ]:           3 :                 } else if (cp < 0x10000) {
     193   [ +  -  +  - ]:           1 :                     if (out && w + 2 < out_cap) {
     194                 :           1 :                         out[w] = (char)(0xE0 | (cp >> 12));
     195                 :           1 :                         out[w + 1] = (char)(0x80 | ((cp >> 6) & 0x3F));
     196                 :           1 :                         out[w + 2] = (char)(0x80 | (cp & 0x3F));
     197                 :             :                     }
     198                 :           1 :                     w += 3;
     199         [ +  - ]:           2 :                 } else if (cp < 0x110000) {
     200   [ +  -  +  - ]:           2 :                     if (out && w + 3 < out_cap) {
     201                 :           2 :                         out[w] = (char)(0xF0 | (cp >> 18));
     202                 :           2 :                         out[w + 1] = (char)(0x80 | ((cp >> 12) & 0x3F));
     203                 :           2 :                         out[w + 2] = (char)(0x80 | ((cp >> 6) & 0x3F));
     204                 :           2 :                         out[w + 3] = (char)(0x80 | (cp & 0x3F));
     205                 :             :                     }
     206                 :           2 :                     w += 4;
     207                 :             :                 }
     208                 :           7 :                 continue; /* already handled, skip the default append */
     209                 :             :             }
     210                 :           1 :             default:
     211                 :           1 :                 return TP_ERR_JSON_SYNTAX;
     212                 :             :             }
     213                 :             :         }
     214   [ +  -  +  - ]:         926 :         if (out && w < out_cap)
     215                 :         926 :             out[w] = c;
     216                 :         926 :         w++;
     217                 :             :     }
     218                 :           1 :     return TP_ERR_JSON_SYNTAX; /* unterminated string */
     219                 :             : }
     220                 :             : 
     221                 :             : /* ── Number parsing ──────────────────────────────────────────────────── */
     222                 :             : 
     223                 :         124 : static tp_result parse_number(json_parser *p, tp_value *val)
     224                 :             : {
     225                 :         124 :     size_t start = p->pos;
     226                 :         124 :     bool is_float = false;
     227                 :         124 :     bool is_neg = false;
     228                 :             : 
     229   [ +  -  +  + ]:         124 :     if (p->pos < p->len && p->src[p->pos] == '-') {
     230                 :           4 :         is_neg = true;
     231                 :           4 :         p->pos++;
     232                 :             :     }
     233                 :             : 
     234                 :             :     /* Integer part */
     235   [ +  -  +  + ]:         124 :     if (p->pos >= p->len || !isdigit((unsigned char)p->src[p->pos]))
     236                 :           1 :         return TP_ERR_JSON_SYNTAX;
     237   [ +  +  +  + ]:         411 :     while (p->pos < p->len && isdigit((unsigned char)p->src[p->pos]))
     238                 :         288 :         p->pos++;
     239                 :             : 
     240                 :             :     /* Fractional part */
     241   [ +  +  +  + ]:         123 :     if (p->pos < p->len && p->src[p->pos] == '.') {
     242                 :          12 :         is_float = true;
     243                 :          12 :         p->pos++;
     244   [ +  -  +  + ]:          12 :         if (p->pos >= p->len || !isdigit((unsigned char)p->src[p->pos]))
     245                 :           1 :             return TP_ERR_JSON_SYNTAX;
     246   [ +  -  +  + ]:          28 :         while (p->pos < p->len && isdigit((unsigned char)p->src[p->pos]))
     247                 :          17 :             p->pos++;
     248                 :             :     }
     249                 :             : 
     250                 :             :     /* Exponent part */
     251   [ +  +  +  +  :         122 :     if (p->pos < p->len && (p->src[p->pos] == 'e' || p->src[p->pos] == 'E')) {
                   +  + ]
     252                 :           5 :         is_float = true;
     253                 :           5 :         p->pos++;
     254   [ +  -  +  +  :           5 :         if (p->pos < p->len && (p->src[p->pos] == '+' || p->src[p->pos] == '-'))
                   +  + ]
     255                 :           3 :             p->pos++;
     256   [ +  -  +  + ]:           5 :         if (p->pos >= p->len || !isdigit((unsigned char)p->src[p->pos]))
     257                 :           2 :             return TP_ERR_JSON_SYNTAX;
     258   [ +  -  +  + ]:           7 :         while (p->pos < p->len && isdigit((unsigned char)p->src[p->pos]))
     259                 :           4 :             p->pos++;
     260                 :             :     }
     261                 :             : 
     262                 :             :     /* Convert */
     263                 :         120 :     size_t numlen = p->pos - start;
     264                 :             :     char tmp[64];
     265         [ +  + ]:         120 :     if (numlen >= sizeof(tmp))
     266                 :           1 :         numlen = sizeof(tmp) - 1;
     267                 :         120 :     memcpy(tmp, p->src + start, numlen);
     268                 :         120 :     tmp[numlen] = '\0';
     269                 :             : 
     270         [ +  + ]:         120 :     if (is_float) {
     271                 :          13 :         double d = strtod(tmp, NULL);
     272                 :          13 :         *val = tp_value_float64(d);
     273         [ +  + ]:         107 :     } else if (is_neg) {
     274                 :           3 :         long long ll = strtoll(tmp, NULL, 10);
     275                 :           3 :         *val = tp_value_int((int64_t)ll);
     276                 :             :     } else {
     277                 :         104 :         unsigned long long ull = strtoull(tmp, NULL, 10);
     278         [ +  + ]:         104 :         if (ull > (unsigned long long)INT64_MAX) {
     279                 :           2 :             *val = tp_value_uint((uint64_t)ull);
     280                 :             :         } else {
     281                 :         102 :             *val = tp_value_int((int64_t)ull);
     282                 :             :         }
     283                 :             :     }
     284                 :         120 :     return TP_OK;
     285                 :             : }
     286                 :             : 
     287                 :             : /* ── Value parsing (recursive) ───────────────────────────────────────── */
     288                 :             : 
     289                 :         134 : static tp_result parse_object(json_parser *p)
     290                 :             : {
     291                 :         134 :     p->depth++;
     292         [ +  + ]:         134 :     if (p->depth > TP_MAX_NESTING_DEPTH)
     293                 :           1 :         return TP_ERR_JSON_DEPTH;
     294                 :             : 
     295         [ -  + ]:         133 :     if (!expect(p, '{'))
     296                 :             :         return TP_ERR_JSON_SYNTAX; /* LCOV_EXCL_LINE */
     297                 :             : 
     298         [ +  + ]:         133 :     if (peek(p) == '}') {
     299                 :           3 :         p->pos++;
     300                 :           3 :         p->depth--;
     301                 :           3 :         return TP_OK;
     302                 :             :     }
     303                 :             : 
     304                 :          78 :     while (true) {
     305                 :             :         /* Parse key */
     306                 :             :         char key[1024];
     307                 :         208 :         size_t key_len = 0;
     308                 :         208 :         tp_result rc = parse_string_into(p, key, sizeof(key) - 1, &key_len);
     309         [ +  + ]:         208 :         if (rc != TP_OK)
     310                 :          50 :             return rc;
     311                 :         207 :         key[key_len] = '\0';
     312                 :             : 
     313                 :         207 :         skip_ws(p);
     314         [ +  + ]:         207 :         if (!expect(p, ':'))
     315                 :           1 :             return TP_ERR_JSON_SYNTAX;
     316                 :             : 
     317                 :             :         /* Push key onto path */
     318                 :             :         size_t saved;
     319                 :         206 :         path_push_key(p, key, key_len, &saved);
     320                 :             : 
     321                 :             :         /* Parse value */
     322                 :         206 :         rc = parse_value(p);
     323         [ +  + ]:         206 :         if (rc != TP_OK)
     324                 :          47 :             return rc;
     325                 :             : 
     326                 :         159 :         path_restore(p, saved);
     327                 :             : 
     328                 :         159 :         skip_ws(p);
     329         [ +  + ]:         159 :         if (peek(p) == '}') {
     330                 :          80 :             p->pos++;
     331                 :          80 :             break;
     332                 :             :         }
     333         [ +  + ]:          79 :         if (!expect(p, ','))
     334                 :           1 :             return TP_ERR_JSON_SYNTAX;
     335                 :             :     }
     336                 :             : 
     337                 :          80 :     p->depth--;
     338                 :          80 :     return TP_OK;
     339                 :             : }
     340                 :             : 
     341                 :          61 : static tp_result parse_array(json_parser *p)
     342                 :             : {
     343                 :          61 :     p->depth++;
     344         [ +  + ]:          61 :     if (p->depth > TP_MAX_NESTING_DEPTH)
     345                 :           1 :         return TP_ERR_JSON_DEPTH;
     346                 :             : 
     347         [ -  + ]:          60 :     if (!expect(p, '['))
     348                 :             :         return TP_ERR_JSON_SYNTAX; /* LCOV_EXCL_LINE */
     349                 :             : 
     350         [ +  + ]:          60 :     if (peek(p) == ']') {
     351                 :           3 :         p->pos++;
     352                 :           3 :         p->depth--;
     353                 :           3 :         return TP_OK;
     354                 :             :     }
     355                 :             : 
     356                 :          57 :     uint32_t idx = 0;
     357                 :          43 :     while (true) {
     358                 :             :         size_t saved;
     359                 :         100 :         path_push_index(p, idx, &saved);
     360                 :             : 
     361                 :         100 :         tp_result rc = parse_value(p);
     362         [ +  + ]:         100 :         if (rc != TP_OK)
     363                 :          33 :             return rc;
     364                 :             : 
     365                 :          68 :         path_restore(p, saved);
     366                 :          68 :         idx++;
     367                 :             : 
     368                 :          68 :         skip_ws(p);
     369         [ +  + ]:          68 :         if (peek(p) == ']') {
     370                 :          24 :             p->pos++;
     371                 :          24 :             break;
     372                 :             :         }
     373         [ +  + ]:          44 :         if (!expect(p, ','))
     374                 :           1 :             return TP_ERR_JSON_SYNTAX;
     375                 :             :     }
     376                 :             : 
     377                 :          24 :     p->depth--;
     378                 :          24 :     return TP_OK;
     379                 :             : }
     380                 :             : 
     381                 :         306 : static tp_result parse_value(json_parser *p)
     382                 :             : {
     383                 :         306 :     skip_ws(p);
     384         [ +  + ]:         306 :     if (p->pos >= p->len)
     385                 :           1 :         return TP_ERR_JSON_SYNTAX;
     386                 :             : 
     387                 :         305 :     char c = p->src[p->pos];
     388                 :             : 
     389         [ +  + ]:         305 :     if (c == '{')
     390                 :          52 :         return parse_object(p);
     391                 :             : 
     392         [ +  + ]:         253 :     if (c == '[')
     393                 :          53 :         return parse_array(p);
     394                 :             : 
     395         [ +  + ]:         200 :     if (c == '"') {
     396                 :             :         /* String value — parse then store at current path */
     397                 :             :         char str[4096];
     398                 :          53 :         size_t slen = 0;
     399                 :          53 :         tp_result rc = parse_string_into(p, str, sizeof(str) - 1, &slen);
     400         [ +  + ]:          53 :         if (rc != TP_OK)
     401                 :           9 :             return rc;
     402                 :          44 :         str[slen] = '\0';
     403                 :          44 :         tp_value val = tp_value_string_n(str, slen);
     404                 :          44 :         return tp_encoder_add_n(p->enc, p->path, p->path_len, &val);
     405                 :             :     }
     406                 :             : 
     407   [ +  +  +  + ]:         147 :     if (c == '-' || isdigit((unsigned char)c)) {
     408                 :             :         tp_value val;
     409                 :         124 :         tp_result rc = parse_number(p, &val);
     410         [ +  + ]:         124 :         if (rc != TP_OK)
     411                 :           4 :             return rc;
     412                 :         120 :         return tp_encoder_add_n(p->enc, p->path, p->path_len, &val);
     413                 :             :     }
     414                 :             : 
     415   [ +  +  +  + ]:          23 :     if (p->pos + 4 <= p->len && memcmp(p->src + p->pos, "true", 4) == 0) {
     416                 :          10 :         p->pos += 4;
     417                 :          10 :         tp_value val = tp_value_bool(true);
     418                 :          10 :         return tp_encoder_add_n(p->enc, p->path, p->path_len, &val);
     419                 :             :     }
     420                 :             : 
     421   [ +  +  +  + ]:          13 :     if (p->pos + 5 <= p->len && memcmp(p->src + p->pos, "false", 5) == 0) {
     422                 :           6 :         p->pos += 5;
     423                 :           6 :         tp_value val = tp_value_bool(false);
     424                 :           6 :         return tp_encoder_add_n(p->enc, p->path, p->path_len, &val);
     425                 :             :     }
     426                 :             : 
     427   [ +  +  +  - ]:           7 :     if (p->pos + 4 <= p->len && memcmp(p->src + p->pos, "null", 4) == 0) {
     428                 :           6 :         p->pos += 4;
     429                 :           6 :         tp_value val = tp_value_null();
     430                 :           6 :         return tp_encoder_add_n(p->enc, p->path, p->path_len, &val);
     431                 :             :     }
     432                 :             : 
     433                 :           1 :     return TP_ERR_JSON_SYNTAX;
     434                 :             : }
     435                 :             : 
     436                 :             : /* ── One-shot encode ─────────────────────────────────────────────────── */
     437                 :             : 
     438                 :          96 : tp_result tp_json_encode(const char *json_str, size_t json_len, uint8_t **buf, size_t *buf_len)
     439                 :             : {
     440   [ +  +  +  +  :          96 :     if (!json_str || !buf || !buf_len)
                   +  + ]
     441                 :           3 :         return TP_ERR_INVALID_PARAM;
     442                 :             : 
     443                 :             :     /* Allocation failure paths are excluded from coverage (LCOV_EXCL). */
     444                 :          93 :     tp_encoder *enc = NULL;
     445                 :          93 :     tp_result rc = tp_encoder_create(&enc);
     446         [ -  + ]:          93 :     if (rc != TP_OK)
     447                 :             :         return rc; /* LCOV_EXCL_LINE */
     448                 :             : 
     449                 :             :     json_parser parser;
     450                 :          93 :     memset(&parser, 0, sizeof(parser));
     451                 :          93 :     parser.src = json_str;
     452                 :          93 :     parser.len = json_len;
     453                 :          93 :     parser.pos = 0;
     454                 :          93 :     parser.depth = 0;
     455                 :          93 :     parser.enc = enc;
     456                 :          93 :     parser.path_len = 0;
     457                 :          93 :     parser.path[0] = '\0';
     458                 :             : 
     459                 :             :     /* Determine root type and parse */
     460                 :          93 :     skip_ws(&parser);
     461         [ +  + ]:          93 :     if (parser.pos >= parser.len) {
     462                 :           2 :         tp_encoder_destroy(&enc);
     463                 :           2 :         return TP_ERR_JSON_SYNTAX;
     464                 :             :     }
     465                 :             : 
     466                 :             :     uint32_t root_type;
     467                 :          91 :     char root_c = parser.src[parser.pos];
     468         [ +  + ]:          91 :     if (root_c == '{') {
     469                 :          82 :         root_type = TP_JSON_ROOT_OBJECT;
     470                 :          82 :         rc = parse_object(&parser);
     471         [ +  + ]:           9 :     } else if (root_c == '[') {
     472                 :           8 :         root_type = TP_JSON_ROOT_ARRAY;
     473                 :           8 :         rc = parse_array(&parser);
     474                 :             :     } else {
     475                 :           1 :         tp_encoder_destroy(&enc);
     476                 :           1 :         return TP_ERR_JSON_SYNTAX;
     477                 :             :     }
     478                 :             : 
     479         [ +  + ]:          90 :     if (rc != TP_OK) {
     480                 :             :         /* LCOV_EXCL_START */
     481                 :             :         tp_encoder_destroy(&enc);
     482                 :             :         return rc;
     483                 :             :         /* LCOV_EXCL_STOP */
     484                 :             :     }
     485                 :             : 
     486                 :             :     /* Store root type metadata */
     487                 :          69 :     tp_value root_val = tp_value_uint(root_type);
     488                 :          69 :     rc = tp_encoder_add(enc, TP_JSON_META_ROOT, &root_val);
     489         [ -  + ]:          69 :     if (rc != TP_OK) {
     490                 :             :         /* LCOV_EXCL_START */
     491                 :             :         tp_encoder_destroy(&enc);
     492                 :             :         return rc;
     493                 :             :         /* LCOV_EXCL_STOP */
     494                 :             :     }
     495                 :             : 
     496                 :          69 :     rc = tp_encoder_build(enc, buf, buf_len);
     497                 :          69 :     tp_encoder_destroy(&enc);
     498                 :          69 :     return rc;
     499                 :             : }
        

Generated by: LCOV version 2.0-1