LCOV - code coverage report
Current view: top level - shared - json.h (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 17 28 60.7 %
Date: 2019-08-23 13:36:53 Functions: 9 12 75.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 2 8 25.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : #pragma once
       3                 :            : 
       4                 :            : #include <stdbool.h>
       5                 :            : #include <stddef.h>
       6                 :            : #include <stdint.h>
       7                 :            : #include <stdio.h>
       8                 :            : 
       9                 :            : #include "macro.h"
      10                 :            : #include "string-util.h"
      11                 :            : #include "log.h"
      12                 :            : 
      13                 :            : /*
      14                 :            :   In case you wonder why we have our own JSON implementation, here are a couple of reasons why this implementation has
      15                 :            :   benefits over various other implementations:
      16                 :            : 
      17                 :            :   - We need support for 64bit signed and unsigned integers, i.e. the full 64,5bit range of -9223372036854775808…18446744073709551615
      18                 :            :   - All our variants are immutable after creation
      19                 :            :   - Special values such as true, false, zero, null, empty strings, empty array, empty objects require zero dynamic memory
      20                 :            :   - Progressive parsing
      21                 :            :   - Our integer/real type implicitly converts, but only if that's safe and loss-lessly possible
      22                 :            :   - There's a "builder" for putting together objects easily in varargs function calls
      23                 :            :   - There's a "dispatcher" for mapping objects to C data structures
      24                 :            :   - Every variant optionally carries parsing location information, which simplifies debugging and parse log error generation
      25                 :            :   - Formatter has color, line, column support
      26                 :            : 
      27                 :            :   Limitations:
      28                 :            :   - Doesn't allow embedded NUL in strings
      29                 :            :   - Can't store integers outside of the -9223372036854775808…18446744073709551615 range (it will use 'long double' for
      30                 :            :     values outside this range, which is lossy)
      31                 :            :   - Can't store negative zero (will be treated identical to positive zero, and not retained across serialization)
      32                 :            :   - Can't store non-integer numbers that can't be stored in "long double" losslessly
      33                 :            :   - Allows creation and parsing of objects with duplicate keys. The "dispatcher" will refuse them however. This means
      34                 :            :     we can parse and pass around such objects, but will carefully refuse them when we convert them into our own data.
      35                 :            : 
      36                 :            :   (These limitations should be pretty much in line with those of other JSON implementations, in fact might be less
      37                 :            :   limiting in most cases even.)
      38                 :            : */
      39                 :            : 
      40                 :            : typedef struct JsonVariant JsonVariant;
      41                 :            : 
      42                 :            : typedef enum JsonVariantType {
      43                 :            :         JSON_VARIANT_STRING,
      44                 :            :         JSON_VARIANT_INTEGER,
      45                 :            :         JSON_VARIANT_UNSIGNED,
      46                 :            :         JSON_VARIANT_REAL,
      47                 :            :         JSON_VARIANT_NUMBER, /* This a pseudo-type: we can never create variants of this type, but we use it as wildcard check for the above three types */
      48                 :            :         JSON_VARIANT_BOOLEAN,
      49                 :            :         JSON_VARIANT_ARRAY,
      50                 :            :         JSON_VARIANT_OBJECT,
      51                 :            :         JSON_VARIANT_NULL,
      52                 :            :         _JSON_VARIANT_TYPE_MAX,
      53                 :            :         _JSON_VARIANT_TYPE_INVALID = -1
      54                 :            : } JsonVariantType;
      55                 :            : 
      56                 :            : int json_variant_new_stringn(JsonVariant **ret, const char *s, size_t n);
      57                 :            : int json_variant_new_integer(JsonVariant **ret, intmax_t i);
      58                 :            : int json_variant_new_unsigned(JsonVariant **ret, uintmax_t u);
      59                 :            : int json_variant_new_real(JsonVariant **ret, long double d);
      60                 :            : int json_variant_new_boolean(JsonVariant **ret, bool b);
      61                 :            : int json_variant_new_array(JsonVariant **ret, JsonVariant **array, size_t n);
      62                 :            : int json_variant_new_array_bytes(JsonVariant **ret, const void *p, size_t n);
      63                 :            : int json_variant_new_array_strv(JsonVariant **ret, char **l);
      64                 :            : int json_variant_new_object(JsonVariant **ret, JsonVariant **array, size_t n);
      65                 :            : int json_variant_new_null(JsonVariant **ret);
      66                 :            : 
      67                 :       9780 : static inline int json_variant_new_string(JsonVariant **ret, const char *s) {
      68                 :       9780 :         return json_variant_new_stringn(ret, s, (size_t) -1);
      69                 :            : }
      70                 :            : 
      71                 :            : JsonVariant *json_variant_ref(JsonVariant *v);
      72                 :            : JsonVariant *json_variant_unref(JsonVariant *v);
      73                 :            : void json_variant_unref_many(JsonVariant **array, size_t n);
      74                 :            : 
      75         [ +  + ]:      81890 : DEFINE_TRIVIAL_CLEANUP_FUNC(JsonVariant *, json_variant_unref);
      76                 :            : 
      77                 :            : const char *json_variant_string(JsonVariant *v);
      78                 :            : intmax_t json_variant_integer(JsonVariant *v);
      79                 :            : uintmax_t json_variant_unsigned(JsonVariant *v);
      80                 :            : long double json_variant_real(JsonVariant *v);
      81                 :            : bool json_variant_boolean(JsonVariant *v);
      82                 :            : 
      83                 :            : JsonVariantType json_variant_type(JsonVariant *v);
      84                 :            : bool json_variant_has_type(JsonVariant *v, JsonVariantType type);
      85                 :            : 
      86                 :      16492 : static inline bool json_variant_is_string(JsonVariant *v) {
      87                 :      16492 :         return json_variant_has_type(v, JSON_VARIANT_STRING);
      88                 :            : }
      89                 :            : 
      90                 :         52 : static inline bool json_variant_is_integer(JsonVariant *v) {
      91                 :         52 :         return json_variant_has_type(v, JSON_VARIANT_INTEGER);
      92                 :            : }
      93                 :            : 
      94                 :         52 : static inline bool json_variant_is_unsigned(JsonVariant *v) {
      95                 :         52 :         return json_variant_has_type(v, JSON_VARIANT_UNSIGNED);
      96                 :            : }
      97                 :            : 
      98                 :         52 : static inline bool json_variant_is_real(JsonVariant *v) {
      99                 :         52 :         return json_variant_has_type(v, JSON_VARIANT_REAL);
     100                 :            : }
     101                 :            : 
     102                 :         52 : static inline bool json_variant_is_number(JsonVariant *v) {
     103                 :         52 :         return json_variant_has_type(v, JSON_VARIANT_NUMBER);
     104                 :            : }
     105                 :            : 
     106                 :        520 : static inline bool json_variant_is_boolean(JsonVariant *v) {
     107                 :        520 :         return json_variant_has_type(v, JSON_VARIANT_BOOLEAN);
     108                 :            : }
     109                 :            : 
     110                 :          0 : static inline bool json_variant_is_array(JsonVariant *v) {
     111                 :          0 :         return json_variant_has_type(v, JSON_VARIANT_ARRAY);
     112                 :            : }
     113                 :            : 
     114                 :       5136 : static inline bool json_variant_is_object(JsonVariant *v) {
     115                 :       5136 :         return json_variant_has_type(v, JSON_VARIANT_OBJECT);
     116                 :            : }
     117                 :            : 
     118                 :          0 : static inline bool json_variant_is_null(JsonVariant *v) {
     119                 :          0 :         return json_variant_has_type(v, JSON_VARIANT_NULL);
     120                 :            : }
     121                 :            : 
     122                 :            : bool json_variant_is_negative(JsonVariant *v);
     123                 :            : 
     124                 :            : size_t json_variant_elements(JsonVariant *v);
     125                 :            : JsonVariant *json_variant_by_index(JsonVariant *v, size_t index);
     126                 :            : JsonVariant *json_variant_by_key(JsonVariant *v, const char *key);
     127                 :            : JsonVariant *json_variant_by_key_full(JsonVariant *v, const char *key, JsonVariant **ret_key);
     128                 :            : 
     129                 :            : bool json_variant_equal(JsonVariant *a, JsonVariant *b);
     130                 :            : 
     131                 :            : struct json_variant_foreach_state {
     132                 :            :         JsonVariant *variant;
     133                 :            :         size_t idx;
     134                 :            : };
     135                 :            : 
     136                 :            : #define JSON_VARIANT_ARRAY_FOREACH(i, v)                                \
     137                 :            :         for (struct json_variant_foreach_state _state = { (v), 0 };     \
     138                 :            :              json_variant_is_array(_state.variant) &&                   \
     139                 :            :                      _state.idx < json_variant_elements(_state.variant) && \
     140                 :            :                      ({ i = json_variant_by_index(_state.variant, _state.idx); \
     141                 :            :                              true; });                                  \
     142                 :            :              _state.idx++)
     143                 :            : 
     144                 :            : #define JSON_VARIANT_OBJECT_FOREACH(k, e, v)                            \
     145                 :            :         for (struct json_variant_foreach_state _state = { (v), 0 };     \
     146                 :            :              json_variant_is_object(_state.variant) &&                  \
     147                 :            :                      _state.idx < json_variant_elements(_state.variant) && \
     148                 :            :                      ({ k = json_variant_string(json_variant_by_index(_state.variant, _state.idx)); \
     149                 :            :                              e = json_variant_by_index(_state.variant, _state.idx + 1); \
     150                 :            :                              true; });                                  \
     151                 :            :              _state.idx += 2)
     152                 :            : 
     153                 :            : int json_variant_get_source(JsonVariant *v, const char **ret_source, unsigned *ret_line, unsigned *ret_column);
     154                 :            : 
     155                 :            : typedef enum JsonFormatFlags {
     156                 :            :         JSON_FORMAT_NEWLINE    = 1 << 0, /* suffix with newline */
     157                 :            :         JSON_FORMAT_PRETTY     = 1 << 1, /* add internal whitespace to appeal to human readers */
     158                 :            :         JSON_FORMAT_COLOR      = 1 << 2, /* insert ANSI color sequences */
     159                 :            :         JSON_FORMAT_COLOR_AUTO = 1 << 3, /* insert ANSI color sequences if colors_enabled() says so */
     160                 :            :         JSON_FORMAT_SOURCE     = 1 << 4, /* prefix with source filename/line/column */
     161                 :            :         JSON_FORMAT_SSE        = 1 << 5, /* prefix/suffix with W3C server-sent events */
     162                 :            :         JSON_FORMAT_SEQ        = 1 << 6, /* prefix/suffix with RFC 7464 application/json-seq */
     163                 :            : } JsonFormatFlags;
     164                 :            : 
     165                 :            : int json_variant_format(JsonVariant *v, JsonFormatFlags flags, char **ret);
     166                 :            : void json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const char *prefix);
     167                 :            : 
     168                 :            : int json_parse(const char *string, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
     169                 :            : int json_parse_continue(const char **p, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
     170                 :            : int json_parse_file(FILE *f, const char *path, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
     171                 :            : 
     172                 :            : enum {
     173                 :            :         _JSON_BUILD_STRING,
     174                 :            :         _JSON_BUILD_INTEGER,
     175                 :            :         _JSON_BUILD_UNSIGNED,
     176                 :            :         _JSON_BUILD_REAL,
     177                 :            :         _JSON_BUILD_BOOLEAN,
     178                 :            :         _JSON_BUILD_ARRAY_BEGIN,
     179                 :            :         _JSON_BUILD_ARRAY_END,
     180                 :            :         _JSON_BUILD_OBJECT_BEGIN,
     181                 :            :         _JSON_BUILD_OBJECT_END,
     182                 :            :         _JSON_BUILD_PAIR,
     183                 :            :         _JSON_BUILD_PAIR_CONDITION,
     184                 :            :         _JSON_BUILD_NULL,
     185                 :            :         _JSON_BUILD_VARIANT,
     186                 :            :         _JSON_BUILD_LITERAL,
     187                 :            :         _JSON_BUILD_STRV,
     188                 :            :         _JSON_BUILD_MAX,
     189                 :            : };
     190                 :            : 
     191                 :            : #define JSON_BUILD_STRING(s) _JSON_BUILD_STRING, ({ const char *_x = s; _x; })
     192                 :            : #define JSON_BUILD_INTEGER(i) _JSON_BUILD_INTEGER, ({ intmax_t _x = i; _x; })
     193                 :            : #define JSON_BUILD_UNSIGNED(u) _JSON_BUILD_UNSIGNED, ({ uintmax_t _x = u; _x; })
     194                 :            : #define JSON_BUILD_REAL(d) _JSON_BUILD_REAL, ({ long double _x = d; _x; })
     195                 :            : #define JSON_BUILD_BOOLEAN(b) _JSON_BUILD_BOOLEAN, ({ bool _x = b; _x; })
     196                 :            : #define JSON_BUILD_ARRAY(...) _JSON_BUILD_ARRAY_BEGIN, __VA_ARGS__, _JSON_BUILD_ARRAY_END
     197                 :            : #define JSON_BUILD_OBJECT(...) _JSON_BUILD_OBJECT_BEGIN, __VA_ARGS__, _JSON_BUILD_OBJECT_END
     198                 :            : #define JSON_BUILD_PAIR(n, ...) _JSON_BUILD_PAIR, ({ const char *_x = n; _x; }), __VA_ARGS__
     199                 :            : #define JSON_BUILD_PAIR_CONDITION(c, n, ...) _JSON_BUILD_PAIR_CONDITION, ({ bool _x = c; _x; }), ({ const char *_x = n; _x; }), __VA_ARGS__
     200                 :            : #define JSON_BUILD_NULL _JSON_BUILD_NULL
     201                 :            : #define JSON_BUILD_VARIANT(v) _JSON_BUILD_VARIANT, ({ JsonVariant *_x = v; _x; })
     202                 :            : #define JSON_BUILD_LITERAL(l) _JSON_BUILD_LITERAL, ({ const char *_x = l; _x; })
     203                 :            : #define JSON_BUILD_STRV(l) _JSON_BUILD_STRV, ({ char **_x = l; _x; })
     204                 :            : 
     205                 :            : int json_build(JsonVariant **ret, ...);
     206                 :            : int json_buildv(JsonVariant **ret, va_list ap);
     207                 :            : 
     208                 :            : /* A bitmask of flags used by the dispatch logic. Note that this is a combined bit mask, that is generated from the bit
     209                 :            :  * mask originally passed into json_dispatch(), the individual bitmask associated with the static JsonDispatch callout
     210                 :            :  * entry, as well the bitmask specified for json_log() calls */
     211                 :            : typedef enum JsonDispatchFlags {
     212                 :            :         /* The following three may be set in JsonDispatch's .flags field or the json_dispatch() flags parameter  */
     213                 :            :         JSON_PERMISSIVE = 1 << 0, /* Shall parsing errors be considered fatal for this property? */
     214                 :            :         JSON_MANDATORY  = 1 << 1, /* Should existence of this property be mandatory? */
     215                 :            :         JSON_LOG        = 1 << 2, /* Should the parser log about errors? */
     216                 :            : 
     217                 :            :         /* The following two may be passed into log_json() in addition to the three above */
     218                 :            :         JSON_DEBUG      = 1 << 3, /* Indicates that this log message is a debug message */
     219                 :            :         JSON_WARNING    = 1 << 4, /* Indicates that this log message is a warning message */
     220                 :            : } JsonDispatchFlags;
     221                 :            : 
     222                 :            : typedef int (*JsonDispatchCallback)(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
     223                 :            : 
     224                 :            : typedef struct JsonDispatch {
     225                 :            :         const char *name;
     226                 :            :         JsonVariantType type;
     227                 :            :         JsonDispatchCallback callback;
     228                 :            :         size_t offset;
     229                 :            :         JsonDispatchFlags flags;
     230                 :            : } JsonDispatch;
     231                 :            : 
     232                 :            : int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallback bad, JsonDispatchFlags flags, void *userdata);
     233                 :            : 
     234                 :            : int json_dispatch_string(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
     235                 :            : int json_dispatch_strv(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
     236                 :            : int json_dispatch_boolean(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
     237                 :            : int json_dispatch_tristate(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
     238                 :            : int json_dispatch_variant(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
     239                 :            : int json_dispatch_integer(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
     240                 :            : int json_dispatch_unsigned(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
     241                 :            : int json_dispatch_uint32(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
     242                 :            : int json_dispatch_int32(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
     243                 :            : 
     244                 :            : assert_cc(sizeof(uintmax_t) == sizeof(uint64_t));
     245                 :            : #define json_dispatch_uint64 json_dispatch_unsigned
     246                 :            : 
     247                 :            : assert_cc(sizeof(intmax_t) == sizeof(int64_t));
     248                 :            : #define json_dispatch_int64 json_dispatch_integer
     249                 :            : 
     250                 :          0 : static inline int json_dispatch_level(JsonDispatchFlags flags) {
     251                 :            : 
     252                 :            :         /* Did the user request no logging? If so, then never log higher than LOG_DEBUG. Also, if this is marked as
     253                 :            :          * debug message, then also log at debug level. */
     254                 :            : 
     255         [ #  # ]:          0 :         if (!(flags & JSON_LOG) ||
     256         [ #  # ]:          0 :             (flags & JSON_DEBUG))
     257                 :          0 :                 return LOG_DEBUG;
     258                 :            : 
     259                 :            :         /* Are we invoked in permissive mode, or is this explicitly marked as warning message? Then this should be
     260                 :            :          * printed at LOG_WARNING */
     261         [ #  # ]:          0 :         if (flags & (JSON_PERMISSIVE|JSON_WARNING))
     262                 :          0 :                 return LOG_WARNING;
     263                 :            : 
     264                 :            :         /* Otherwise it's an error. */
     265                 :          0 :         return LOG_ERR;
     266                 :            : }
     267                 :            : 
     268                 :            : int json_log_internal(JsonVariant *variant, int level, int error, const char *file, int line, const char *func, const char *format, ...)  _printf_(7, 8);
     269                 :            : 
     270                 :            : #define json_log(variant, flags, error, ...)                            \
     271                 :            :         ({                                                              \
     272                 :            :                 int _level = json_dispatch_level(flags), _e = (error);  \
     273                 :            :                 (log_get_max_level() >= LOG_PRI(_level))                \
     274                 :            :                         ? json_log_internal(variant, _level, _e, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__) \
     275                 :            :                         : -ERRNO_VALUE(_e);                             \
     276                 :            :         })
     277                 :            : 
     278                 :            : #define JSON_VARIANT_STRING_CONST(x) _JSON_VARIANT_STRING_CONST(UNIQ, (x))
     279                 :            : 
     280                 :            : #define _JSON_VARIANT_STRING_CONST(xq, x)                               \
     281                 :            :         ({                                                              \
     282                 :            :                 _align_(2) static const char UNIQ_T(json_string_const, xq)[] = (x); \
     283                 :            :                 assert((((uintptr_t) UNIQ_T(json_string_const, xq)) & 1) == 0); \
     284                 :            :                 (JsonVariant*) ((uintptr_t) UNIQ_T(json_string_const, xq) + 1); \
     285                 :            :         })
     286                 :            : 
     287                 :            : const char *json_variant_type_to_string(JsonVariantType t);
     288                 :            : JsonVariantType json_variant_type_from_string(const char *s);

Generated by: LCOV version 1.14