static void test_one(const char *data, ...) { void *state = NULL; va_list ap; va_start(ap, data); for (;;) { _cleanup_free_ char *str = NULL; union json_value v = {}; int t, tt; t = json_tokenize(&data, &str, &v, &state, NULL); tt = va_arg(ap, int); assert_se(t == tt); if (t == JSON_END || t < 0) break; else if (t == JSON_STRING) { const char *nn; nn = va_arg(ap, const char *); assert_se(streq_ptr(nn, str)); } else if (t == JSON_REAL) { double d; d = va_arg(ap, double); assert_se(fabs(d - v.real) < 0.001); } else if (t == JSON_INTEGER) {
static int parse_id(const void *payload, size_t size, char **ret) { _cleanup_free_ char *buf = NULL, *id = NULL, *other = NULL; union json_value v = {}; void *json_state = NULL; const char *p; int t; assert(payload); assert(ret); if (size <= 0) return -EBADMSG; if (memchr(payload, 0, size)) return -EBADMSG; buf = strndup(payload, size); if (!buf) return -ENOMEM; p = buf; t = json_tokenize(&p, &id, &v, &json_state, NULL); if (t < 0) return t; if (t != JSON_STRING) return -EBADMSG; t = json_tokenize(&p, &other, &v, &json_state, NULL); if (t < 0) return t; if (t != JSON_END) return -EBADMSG; if (!dkr_id_is_valid(id)) return -EBADMSG; *ret = id; id = NULL; return 0; }
static int parse_ancestry(const void *payload, size_t size, char ***ret) { _cleanup_free_ char *buf = NULL; void *json_state = NULL; const char *p; enum { STATE_BEGIN, STATE_ITEM, STATE_COMMA, STATE_END, } state = STATE_BEGIN; _cleanup_strv_free_ char **l = NULL; size_t n = 0, allocated = 0; if (size <= 0) return -EBADMSG; if (memchr(payload, 0, size)) return -EBADMSG; buf = strndup(payload, size); if (!buf) return -ENOMEM; p = buf; for (;;) { _cleanup_free_ char *str; union json_value v = {}; int t; t = json_tokenize(&p, &str, &v, &json_state, NULL); if (t < 0) return t; switch (state) { case STATE_BEGIN: if (t == JSON_ARRAY_OPEN) state = STATE_ITEM; else return -EBADMSG; break; case STATE_ITEM: if (t == JSON_STRING) { if (!dkr_id_is_valid(str)) return -EBADMSG; if (n+1 > LAYERS_MAX) return -EFBIG; if (!GREEDY_REALLOC(l, allocated, n + 2)) return -ENOMEM; l[n++] = str; str = NULL; l[n] = NULL; state = STATE_COMMA; } else if (t == JSON_ARRAY_CLOSE) state = STATE_END; else return -EBADMSG; break; case STATE_COMMA: if (t == JSON_COMMA) state = STATE_ITEM; else if (t == JSON_ARRAY_CLOSE) state = STATE_END; else return -EBADMSG; break; case STATE_END: if (t == JSON_END) { if (strv_isempty(l)) return -EBADMSG; if (!strv_is_uniq(l)) return -EBADMSG; l = strv_reverse(l); *ret = l; l = NULL; return 0; } else return -EBADMSG; } } }
static int json_tokens(const char *string, size_t size, JsonVariant ***tokens, size_t *n) { _cleanup_free_ char *buf = NULL; _cleanup_(json_variant_array_unrefp) JsonVariant **items = NULL; union json_value v = {}; void *json_state = NULL; const char *p; int t, r; size_t allocated = 0, s = 0; assert(string); assert(n); if (size <= 0) return -EBADMSG; buf = strndup(string, size); if (!buf) return -ENOMEM; p = buf; for (;;) { _cleanup_json_variant_unref_ JsonVariant *var = NULL; _cleanup_free_ char *rstr = NULL; t = json_tokenize(&p, &rstr, &v, &json_state, NULL); if (t < 0) return t; else if (t == JSON_END) break; if (t <= JSON_ARRAY_CLOSE) { r = json_variant_new(&var, JSON_VARIANT_CONTROL); if (r < 0) return r; var->value.integer = t; } else { switch (t) { case JSON_STRING: r = json_variant_new(&var, JSON_VARIANT_STRING); if (r < 0) return r; var->size = strlen(rstr); var->string = strdup(rstr); if (!var->string) { return -ENOMEM; } break; case JSON_INTEGER: r = json_variant_new(&var, JSON_VARIANT_INTEGER); if (r < 0) return r; var->value = v; break; case JSON_REAL: r = json_variant_new(&var, JSON_VARIANT_REAL); if (r < 0) return r; var->value = v; break; case JSON_BOOLEAN: r = json_variant_new(&var, JSON_VARIANT_BOOLEAN); if (r < 0) return r; var->value = v; break; case JSON_NULL: r = json_variant_new(&var, JSON_VARIANT_NULL); if (r < 0) return r; break; } } if (!GREEDY_REALLOC(items, allocated, s+2)) return -ENOMEM; items[s++] = var; items[s] = NULL; var = NULL; } *n = s; *tokens = items; items = NULL; return 0; }