* decrement the refcount, possibly freeing the value. k5_json_retain returns
* its argument and always succeeds. Both functions gracefully accept NULL.
*/
-void *k5_json_retain(k5_json_value val);
+k5_json_value k5_json_retain(k5_json_value val);
void k5_json_release(k5_json_value val);
/*
- * Unless otherwise specified, the following functions return NULL on error
- * (generally only if out of memory) if they return a pointer type, or 0 on
- * success and -1 on failure if they return int.
+ * If a k5_json_* function can fail, it returns 0 on success and an errno value
+ * on failure.
*/
/*
typedef struct k5_json_null_st *k5_json_null;
-k5_json_null k5_json_null_create(void);
+int k5_json_null_create(k5_json_null *null_out);
/*
* Boolean
typedef struct k5_json_bool_st *k5_json_bool;
-k5_json_bool k5_json_bool_create(int truth);
+int k5_json_bool_create(int truth, k5_json_bool *val_out);
int k5_json_bool_value(k5_json_bool bval);
/*
typedef struct k5_json_array_st *k5_json_array;
-k5_json_array k5_json_array_create(void);
+int k5_json_array_create(k5_json_array *val_out);
size_t k5_json_array_length(k5_json_array array);
/* Both of these functions increment the reference count on val. */
typedef void (*k5_json_object_iterator_fn)(void *arg, const char *key,
k5_json_value val);
-k5_json_object k5_json_object_create(void);
+int k5_json_object_create(k5_json_object *val_out);
void k5_json_object_iterate(k5_json_object obj,
k5_json_object_iterator_fn func, void *arg);
typedef struct k5_json_string_st *k5_json_string;
-k5_json_string k5_json_string_create(const char *string);
-k5_json_string k5_json_string_create_len(const void *data, size_t len);
+int k5_json_string_create(const char *cstring, k5_json_string *val_out);
+int k5_json_string_create_len(const void *data, size_t len,
+ k5_json_string *val_out);
const char *k5_json_string_utf8(k5_json_string string);
+
/* Create a base64 string value from binary data. */
-k5_json_string k5_json_string_create_base64(const void *data, size_t len);
+int k5_json_string_create_base64(const void *data, size_t len,
+ k5_json_string *val_out);
-/* Decode a base64 string. Returns NULL and *len_out == 0 if out of memory,
- * NULL and *len == SIZE_MAX if string's contents aren't valid base64. */
-void *k5_json_string_unbase64(k5_json_string string, size_t *len_out);
+/* Decode the base64 contents of string. */
+int k5_json_string_unbase64(k5_json_string string, unsigned char **data_out,
+ size_t *len_out);
/*
* Number
typedef struct k5_json_number_st *k5_json_number;
-k5_json_number k5_json_number_create(long long number);
+int k5_json_number_create(long long number, k5_json_number *val_out);
long long k5_json_number_value(k5_json_number number);
/*
* JSON encoding and decoding
*/
-char *k5_json_encode(k5_json_value val);
-k5_json_value k5_json_decode(const char *str);
+int k5_json_encode(k5_json_value val, char **json_out);
+int k5_json_decode(const char *str, k5_json_value *val_out);
#endif /* K5_JSON_H */
return 0;
}
+static inline k5_json_number
+number(long long nval)
+{
+ k5_json_number num;
+
+ return k5_json_number_create(nval, &num) ? NULL : num;
+}
+
+static inline k5_json_string
+string(const char *cstring)
+{
+ k5_json_string str;
+
+ return k5_json_string_create(cstring, &str) ? NULL : str;
+}
+
+static inline k5_json_string
+base64string(const void *data, size_t len)
+{
+ k5_json_string str;
+
+ return k5_json_string_create_base64(data, len, &str) ? NULL : str;
+}
+
+static inline k5_json_null
+null(void)
+{
+ k5_json_null n;
+
+ return k5_json_null_create(&n) ? NULL : n;
+}
+
+static inline k5_json_bool
+bool(int truth)
+{
+ k5_json_bool b;
+
+ return k5_json_bool_create(truth, &b) ? NULL : b;
+}
+
/* Return a JSON null or string value representing str. */
static k5_json_value
json_optional_string(const char *str)
{
- return (str == NULL) ? (k5_json_value)k5_json_null_create() :
- (k5_json_value)k5_json_string_create(str);
+ return (str == NULL) ? (k5_json_value)null() : string(str);
}
/* Return a JSON null or array value representing princ. */
k5_json_string str;
if (princ == NULL)
- return k5_json_null_create();
+ return null();
if (krb5_unparse_name(context, princ, &princname))
return NULL;
- str = k5_json_string_create(princname);
+ str = string(princname);
krb5_free_unparsed_name(context, princname);
return str;
}
k5_json_array array;
if (etypes == NULL)
- return k5_json_null_create();
- array = k5_json_array_create();
- if (array == NULL)
+ return null();
+ if (k5_json_array_create(&array))
return NULL;
for (; *etypes != 0; etypes++) {
- if (add(array, k5_json_number_create(*etypes)))
+ if (add(array, number(*etypes)))
goto oom;
}
return array;
k5_json_array array;
if (name == NULL)
- return k5_json_null_create();
- array = k5_json_array_create();
- if (array == NULL)
+ return null();
+ if (k5_json_array_create(&array))
return NULL;
if (add(array, json_principal(context, name->princ)))
goto oom;
char name[1024];
if (keytab == NULL)
- return k5_json_null_create();
+ return null();
if (krb5_kt_get_name(context, keytab, name, sizeof(name)))
return NULL;
- return k5_json_string_create(name);
+ return string(name);
}
/* Return a JSON null or string value representing rcache. */
k5_json_string str;
if (rcache == NULL)
- return k5_json_null_create();
+ return null();
if (asprintf(&name, "%s:%s", krb5_rc_get_type(context, rcache),
krb5_rc_get_name(context, rcache)) < 0)
return NULL;
- str = k5_json_string_create(name);
+ str = string(name);
free(name);
return str;
}
{
k5_json_array array;
- array = k5_json_array_create();
- if (array == NULL)
+ if (k5_json_array_create(&array))
return NULL;
- if (add(array, k5_json_number_create(keyblock->enctype)))
+ if (add(array, number(keyblock->enctype)))
goto oom;
- if (add(array, k5_json_string_create_base64(keyblock->contents,
- keyblock->length)))
+ if (add(array, base64string(keyblock->contents, keyblock->length)))
goto oom;
return array;
oom:
{
k5_json_array array;
- array = k5_json_array_create();
- if (array == NULL)
+ if (k5_json_array_create(&array))
return NULL;
- if (add(array, k5_json_number_create(addr->addrtype)))
+ if (add(array, number(addr->addrtype)))
goto oom;
- if (add(array, k5_json_string_create_base64(addr->contents, addr->length)))
+ if (add(array, base64string(addr->contents, addr->length)))
goto oom;
return array;
oom:
k5_json_array array;
if (addrs == NULL)
- return k5_json_null_create();
- array = k5_json_array_create();
- if (array == NULL)
+ return null();
+ if (k5_json_array_create(&array))
return NULL;
for (; *addrs != NULL; addrs++) {
if (add(array, json_address(*addrs))) {
{
k5_json_array array;
- array = k5_json_array_create();
- if (array == NULL)
+ if (k5_json_array_create(&array))
return NULL;
- if (add(array, k5_json_number_create(ad->ad_type)))
+ if (add(array, number(ad->ad_type)))
goto oom;
- if (add(array, k5_json_string_create_base64(ad->contents, ad->length)))
+ if (add(array, base64string(ad->contents, ad->length)))
goto oom;
return array;
oom:
k5_json_array array;
if (authdata == NULL)
- return k5_json_null_create();
- array = k5_json_array_create();
- if (array == NULL)
+ return null();
+ if (k5_json_array_create(&array))
return NULL;
for (; *authdata != NULL; authdata++) {
if (add(array, json_authdata_element(*authdata))) {
{
k5_json_array array;
- array = k5_json_array_create();
- if (array == NULL)
+ if (k5_json_array_create(&array))
return NULL;
if (add(array, json_principal(context, creds->client)))
goto eom;
goto eom;
if (add(array, json_keyblock(&creds->keyblock)))
goto eom;
- if (add(array, k5_json_number_create(creds->times.authtime)))
+ if (add(array, number(creds->times.authtime)))
goto eom;
- if (add(array, k5_json_number_create(creds->times.starttime)))
+ if (add(array, number(creds->times.starttime)))
goto eom;
- if (add(array, k5_json_number_create(creds->times.endtime)))
+ if (add(array, number(creds->times.endtime)))
goto eom;
- if (add(array, k5_json_number_create(creds->times.renew_till)))
+ if (add(array, number(creds->times.renew_till)))
goto eom;
- if (add(array, k5_json_bool_create(creds->is_skey)))
+ if (add(array, bool(creds->is_skey)))
goto eom;
- if (add(array, k5_json_number_create(creds->ticket_flags)))
+ if (add(array, number(creds->ticket_flags)))
goto eom;
if (add(array, json_addresses(creds->addresses)))
goto eom;
- if (add(array, k5_json_string_create_base64(creds->ticket.data,
- creds->ticket.length)))
+ if (add(array, base64string(creds->ticket.data, creds->ticket.length)))
goto eom;
- if (add(array, k5_json_string_create_base64(creds->second_ticket.data,
- creds->second_ticket.length)))
+ if (add(array, base64string(creds->second_ticket.data,
+ creds->second_ticket.length)))
goto eom;
if (add(array, json_authdata(creds->authdata)))
goto eom;
k5_json_array array;
int st;
- array = k5_json_array_create();
- if (array == NULL)
+ if (k5_json_array_create(&array))
return NULL;
/* Put the principal in the first array entry. */
k5_json_string str;
if (ccache == NULL)
- return k5_json_null_create();
+ return null();
if (strcmp(krb5_cc_get_type(context, ccache), "MEMORY") == 0) {
return json_ccache_contents(context, ccache);
} else {
if (krb5_cc_get_full_name(context, ccache, &name))
return NULL;
- str = k5_json_string_create(name);
+ str = string(name);
free(name);
return str;
}
{
k5_json_array array;
- array = k5_json_array_create();
- if (array == NULL)
+ if (k5_json_array_create(&array))
return NULL;
- if (add(array, k5_json_number_create(cred->usage)))
+ if (add(array, number(cred->usage)))
goto oom;
if (add(array, json_kgname(context, cred->name)))
goto oom;
if (add(array, json_principal(context, cred->impersonator)))
goto oom;
- if (add(array, k5_json_bool_create(cred->default_identity)))
+ if (add(array, bool(cred->default_identity)))
goto oom;
- if (add(array, k5_json_bool_create(cred->iakerb_mech)))
+ if (add(array, bool(cred->iakerb_mech)))
goto oom;
/* Don't marshal cred->destroy_ccache. */
if (add(array, json_keytab(context, cred->keytab)))
goto oom;
if (add(array, json_keytab(context, cred->client_keytab)))
goto oom;
- if (add(array, k5_json_bool_create(cred->have_tgt)))
+ if (add(array, bool(cred->have_tgt)))
goto oom;
- if (add(array, k5_json_number_create(cred->expire)))
+ if (add(array, number(cred->expire)))
goto oom;
- if (add(array, k5_json_number_create(cred->refresh_time)))
+ if (add(array, number(cred->refresh_time)))
goto oom;
if (add(array, json_etypes(cred->req_enctypes)))
goto oom;
return status;
cred = (krb5_gss_cred_id_t)cred_handle;
- array = k5_json_array_create();
- if (array == NULL)
+ if (k5_json_array_create(&array))
goto oom;
- if (add(array, k5_json_string_create(CRED_EXPORT_MAGIC)))
+ if (add(array, string(CRED_EXPORT_MAGIC)))
goto oom;
if (add(array, json_kgcred(context, cred)))
goto oom;
- str = k5_json_encode(array);
- if (str == NULL)
+ if (k5_json_encode(array, &str))
goto oom;
d = string2data(str);
if (data_to_gss(&d, token))
s = check_element(array, 1, K5_JSON_TID_STRING);
if (s == NULL)
return -1;
- keyblock->contents = k5_json_string_unbase64(s, &len);
- if (keyblock->contents == NULL)
+ if (k5_json_string_unbase64(s, &keyblock->contents, &len))
return -1;
keyblock->length = len;
keyblock->magic = KV5M_KEYBLOCK;
if (addr == NULL)
return -1;
addr->addrtype = k5_json_number_value(n);
- addr->contents = k5_json_string_unbase64(s, &len);
- if (addr->contents == NULL) {
+ if (k5_json_string_unbase64(s, &addr->contents, &len)) {
free(addr);
return -1;
}
if (ad == NULL)
return -1;
ad->ad_type = k5_json_number_value(n);
- ad->contents = k5_json_string_unbase64(s, &len);
- if (ad->contents == NULL) {
+ if (k5_json_string_unbase64(s, &ad->contents, &len)) {
free(ad);
return -1;
}
k5_json_number n;
k5_json_bool b;
k5_json_string s;
+ unsigned char *data;
size_t len;
memset(creds, 0, sizeof(*creds));
s = check_element(array, 10, K5_JSON_TID_STRING);
if (s == NULL)
goto invalid;
- creds->ticket.data = k5_json_string_unbase64(s, &len);
- if (creds->ticket.data == NULL)
+ if (k5_json_string_unbase64(s, &data, &len))
goto invalid;
+ creds->ticket.data = (char *)data;
creds->ticket.length = len;
s = check_element(array, 11, K5_JSON_TID_STRING);
if (s == NULL)
goto invalid;
- creds->second_ticket.data = k5_json_string_unbase64(s, &len);
- if (creds->second_ticket.data == NULL)
+ if (k5_json_string_unbase64(s, &data, &len))
goto invalid;
+ creds->second_ticket.data = (char *)data;
creds->second_ticket.length = len;
if (json_to_authdata(context, k5_json_array_get(array, 12),
*minor_status = ret;
goto cleanup;
}
- v = k5_json_decode(copy);
- if (v == NULL)
+ if (k5_json_decode(copy, &v))
goto invalid;
/* Decode the CRED_EXPORT_MAGIC array wrapper. */
static krb5_error_code
clear_cc_config_out_data(krb5_context context, krb5_init_creds_context ctx)
{
- if (ctx->cc_config_out != NULL)
- k5_json_release(ctx->cc_config_out);
- ctx->cc_config_out = k5_json_object_create();
- if (ctx->cc_config_out == NULL)
- return ENOMEM;
- return 0;
+ k5_json_release(ctx->cc_config_out);
+ ctx->cc_config_out = NULL;
+ return k5_json_object_create(&ctx->cc_config_out);
}
static krb5_error_code
read_cc_config_in_data(krb5_context context, krb5_init_creds_context ctx)
{
+ k5_json_value val;
krb5_data config;
char *encoded;
krb5_error_code code;
int i;
- if (ctx->cc_config_in != NULL)
- k5_json_release(ctx->cc_config_in);
+ k5_json_release(ctx->cc_config_in);
ctx->cc_config_in = NULL;
if (ctx->opte->opt_private->in_ccache == NULL)
if (i < 0)
return ENOMEM;
- ctx->cc_config_in = k5_json_decode(encoded);
+ code = k5_json_decode(encoded, &val);
free(encoded);
- if (ctx->cc_config_in == NULL)
- return ENOMEM;
- if (k5_json_get_tid(ctx->cc_config_in) != K5_JSON_TID_OBJECT) {
- k5_json_release(ctx->cc_config_in);
- ctx->cc_config_in = NULL;
+ if (code)
+ return code;
+ if (k5_json_get_tid(val) != K5_JSON_TID_OBJECT) {
+ k5_json_release(val);
return EINVAL;
}
-
+ ctx->cc_config_in = val;
return 0;
}
if (ctx->cc_config_out == NULL ||
k5_json_object_count(ctx->cc_config_out) == 0)
return 0;
- encoded = k5_json_encode(ctx->cc_config_out);
- if (encoded == NULL)
- return ENOMEM;
+ code = k5_json_encode(ctx->cc_config_out, &encoded);
+ if (code)
+ return code;
config = string2data(encoded);
code = krb5_cc_set_config(context, ccache, ctx->cred.server,
KRB5_CC_CONF_PA_CONFIG_DATA, &config);
struct krb5_responder_context_st rctx;
krb5_preauthtype selected_preauth_type;
krb5_preauthtype allowed_preauth_type;
- void *cc_config_in;
- void *cc_config_out;
+ k5_json_object cc_config_in;
+ k5_json_object cc_config_out;
/* Discovered offset of server time during preauth */
krb5_timestamp pa_offset;
krb5_int32 pa_offset_usec;
const char *key, const char *data)
{
krb5_init_creds_context ctx = (krb5_init_creds_context)rock;
- k5_json_value value;
- int i;
+ krb5_error_code ret;
+ k5_json_string str;
if (ctx->cc_config_out == NULL)
return ENOENT;
- value = k5_json_string_create(data);
- if (value == NULL)
- return ENOMEM;
-
- i = k5_json_object_set(ctx->cc_config_out, key, value);
- k5_json_release(value);
- if (i < 0)
- return ENOMEM;
+ ret = k5_json_string_create(data, &str);
+ if (ret)
+ return ret;
- return 0;
+ ret = k5_json_object_set(ctx->cc_config_out, key, str);
+ k5_json_release(str);
+ return ret;
}
static struct krb5_clpreauth_callbacks_st callbacks = {
if (data->data == NULL)
return 0;
- str = k5_json_string_create_len(data->data, data->length);
- if (str == NULL)
- return ENOMEM;
+ retval = k5_json_string_create_len(data->data, data->length, &str);
+ if (retval)
+ return retval;
retval = k5_json_object_set(obj, key, str);
k5_json_release(str);
- return retval == 0 ? 0 : ENOMEM;
+ return retval;
}
/* Converts a property of a json object into a krb5_int32. */
if (int32 == -1)
return 0;
- num = k5_json_number_create(int32);
- if (num == NULL)
- return ENOMEM;
+ retval = k5_json_number_create(int32, &num);
+ if (retval)
+ return retval;
retval = k5_json_object_set(obj, key, num);
k5_json_release(num);
- return retval == 0 ? 0 : ENOMEM;
+ return retval;
}
/* Converts a krb5_otp_tokeninfo into a JSON object. */
static krb5_error_code
codec_encode_tokeninfo(krb5_otp_tokeninfo *ti, k5_json_object *out)
{
- krb5_error_code retval = 0;
+ krb5_error_code retval;
k5_json_object obj;
krb5_flags flags;
- obj = k5_json_object_create();
- if (obj == NULL)
+ retval = k5_json_object_create(&obj);
+ if (retval != 0)
goto error;
flags = KRB5_RESPONDER_OTP_FLAGS_COLLECT_TOKEN;
k5_json_object obj = NULL, tmp = NULL;
k5_json_string str = NULL;
k5_json_array arr = NULL;
- krb5_error_code retval = 0;
+ krb5_error_code retval;
int i;
- obj = k5_json_object_create();
- if (obj == NULL)
- goto error;
+ retval = k5_json_object_create(&obj);
+ if (retval != 0)
+ goto cleanup;
if (chl->service.data) {
- str = k5_json_string_create_len(chl->service.data,
- chl->service.length);
- if (str == NULL)
- goto error;
+ retval = k5_json_string_create_len(chl->service.data,
+ chl->service.length, &str);
+ if (retval != 0)
+ goto cleanup;
retval = k5_json_object_set(obj, "service", str);
k5_json_release(str);
- if (retval != 0) {
- retval = ENOMEM;
- goto error;
- }
+ if (retval != 0)
+ goto cleanup;
}
- arr = k5_json_array_create();
- if (arr == NULL)
- goto error;
+ retval = k5_json_array_create(&arr);
+ if (retval != 0)
+ goto cleanup;
for (i = 0; chl->tokeninfo[i] != NULL ; i++) {
retval = codec_encode_tokeninfo(chl->tokeninfo[i], &tmp);
if (retval != 0)
- goto error;
+ goto cleanup;
retval = k5_json_array_add(arr, tmp);
k5_json_release(tmp);
- if (retval != 0) {
- retval = ENOMEM;
- goto error;
- }
- }
-
- if (k5_json_object_set(obj, "tokenInfo", arr) != 0) {
- retval = ENOMEM;
- goto error;
+ if (retval != 0)
+ goto cleanup;
}
- *json = k5_json_encode(obj);
- if (*json == NULL)
- goto error;
+ retval = k5_json_object_set(obj, "tokenInfo", arr);
+ if (retval != 0)
+ goto cleanup;
- k5_json_release(arr);
- k5_json_release(obj);
- return 0;
+ retval = k5_json_encode(obj, json);
+ if (retval)
+ goto cleanup;
-error:
+cleanup:
k5_json_release(arr);
k5_json_release(obj);
- return retval == 0 ? ENOMEM : retval;
+ return retval;
}
/* Converts a JSON object into a krb5_responder_otp_tokeninfo. */
krb5_error_code retval;
size_t i;
- obj = k5_json_decode(json);
- if (obj == NULL)
+ retval = k5_json_decode(json, &obj);
+ if (retval != 0)
goto error;
if (k5_json_get_tid(obj) != K5_JSON_TID_OBJECT)
krb5_otp_tokeninfo **tis, krb5_otp_tokeninfo **ti,
krb5_data *value, krb5_data *pin)
{
- krb5_error_code retval = EBADMSG;
+ krb5_error_code retval;
k5_json_value val = NULL;
krb5_int32 indx, i;
krb5_data tmp;
if (answer == NULL)
return EBADMSG;
- val = k5_json_decode(answer);
- if (val == NULL)
+ retval = k5_json_decode(answer, &val);
+ if (retval != 0)
goto cleanup;
if (k5_json_get_tid(val) != K5_JSON_TID_OBJECT)
{
krb5_error_code retval;
k5_json_object obj = NULL;
- k5_json_value val = NULL;
+ k5_json_number num;
+ k5_json_string str;
char *tmp;
- obj = k5_json_object_create();
- if (obj == NULL)
+ retval = k5_json_object_create(&obj);
+ if (retval != 0)
goto error;
- val = k5_json_number_create(ti);
- if (val == NULL)
+ retval = k5_json_number_create(ti, &num);
+ if (retval != 0)
goto error;
- retval = k5_json_object_set(obj, "tokeninfo", val);
- k5_json_release(val);
+ retval = k5_json_object_set(obj, "tokeninfo", num);
+ k5_json_release(num);
if (retval != 0)
goto error;
if (value != NULL) {
- val = k5_json_string_create(value);
- if (val == NULL)
+ retval = k5_json_string_create(value, &str);
+ if (retval != 0)
goto error;
- retval = k5_json_object_set(obj, "value", val);
- k5_json_release(val);
+ retval = k5_json_object_set(obj, "value", str);
+ k5_json_release(str);
if (retval != 0)
goto error;
}
if (pin != NULL) {
- val = k5_json_string_create(pin);
- if (val == NULL)
+ retval = k5_json_string_create(pin, &str);
+ if (retval != 0)
goto error;
- retval = k5_json_object_set(obj, "pin", val);
- k5_json_release(val);
+ retval = k5_json_object_set(obj, "pin", str);
+ k5_json_release(str);
if (retval != 0)
goto error;
}
- tmp = k5_json_encode(obj);
- k5_json_release(obj);
- if (tmp == NULL)
+ retval = k5_json_encode(obj, &tmp);
+ if (retval != 0)
goto error;
+ k5_json_release(obj);
retval = krb5_responder_set_answer(ctx, rctx, KRB5_RESPONDER_QUESTION_OTP,
tmp);
error:
k5_json_release(obj);
- return ENOMEM;
+ return retval;
}
void KRB5_CALLCONV
#define PTR2BASE(ptr) (((struct value_base *)ptr) - 1)
#define BASE2PTR(ptr) ((void *)(((struct value_base *)ptr) + 1))
-void *
+k5_json_value
k5_json_retain(k5_json_value val)
{
struct value_base *p;
static struct json_type_st null_type = { K5_JSON_TID_NULL, "null", NULL };
-k5_json_null
-k5_json_null_create(void)
+int
+k5_json_null_create(k5_json_null *val_out)
{
- return alloc_value(&null_type, 0);
+ *val_out = alloc_value(&null_type, 0);
+ return (*val_out == NULL) ? ENOMEM : 0;
}
/*** Boolean type ***/
static struct json_type_st bool_type = { K5_JSON_TID_BOOL, "bool", NULL };
-k5_json_bool
-k5_json_bool_create(int truth)
+int
+k5_json_bool_create(int truth, k5_json_bool *val_out)
{
k5_json_bool b;
+ *val_out = NULL;
b = alloc_value(&bool_type, 1);
+ if (b == NULL)
+ return ENOMEM;
*(unsigned char *)b = !!truth;
- return b;
+ *val_out = b;
+ return 0;
}
int
K5_JSON_TID_ARRAY, "array", array_dealloc
};
-k5_json_array
-k5_json_array_create(void)
+int
+k5_json_array_create(k5_json_array *val_out)
{
- return alloc_value(&array_type, sizeof(struct k5_json_array_st));
+ *val_out = alloc_value(&array_type, sizeof(struct k5_json_array_st));
+ return (*val_out == NULL) ? ENOMEM : 0;
}
int
K5_JSON_TID_OBJECT, "object", object_dealloc
};
-k5_json_object
-k5_json_object_create(void)
+int
+k5_json_object_create(k5_json_object *val_out)
{
- return alloc_value(&object_type, sizeof(struct k5_json_object_st));
+ *val_out = alloc_value(&object_type, sizeof(struct k5_json_object_st));
+ return (*val_out == NULL) ? ENOMEM : 0;
}
size_t
K5_JSON_TID_STRING, "string", NULL
};
-k5_json_string
-k5_json_string_create(const char *string)
+int
+k5_json_string_create(const char *cstring, k5_json_string *val_out)
{
- return k5_json_string_create_len(string, strlen(string));
+ return k5_json_string_create_len(cstring, strlen(cstring), val_out);
}
-k5_json_string
-k5_json_string_create_len(const void *data, size_t len)
+int
+k5_json_string_create_len(const void *data, size_t len,
+ k5_json_string *val_out)
{
char *s;
+ *val_out = NULL;
s = alloc_value(&string_type, len + 1);
if (s == NULL)
- return NULL;
+ return ENOMEM;
memcpy(s, data, len);
s[len] = '\0';
- return (k5_json_string)s;
+ *val_out = (k5_json_string)s;
+ return 0;
}
-k5_json_string
-k5_json_string_create_base64(const void *data, size_t len)
+int
+k5_json_string_create_base64(const void *data, size_t len,
+ k5_json_string *val_out)
{
char *base64;
- k5_json_string s;
+ int ret;
+ *val_out = NULL;
base64 = k5_base64_encode(data, len);
if (base64 == NULL)
- return NULL;
- s = k5_json_string_create(base64);
+ return ENOMEM;
+ ret = k5_json_string_create(base64, val_out);
free(base64);
- return s;
+ return ret;
}
const char *
return (const char *)string;
}
-void *
-k5_json_string_unbase64(k5_json_string string, size_t *len_out)
+int
+k5_json_string_unbase64(k5_json_string string, unsigned char **data_out,
+ size_t *len_out)
{
- return k5_base64_decode((const char *)string, len_out);
+ unsigned char *data;
+ size_t len;
+
+ *data_out = NULL;
+ *len_out = 0;
+ data = k5_base64_decode((const char *)string, &len);
+ if (data == NULL)
+ return (len == 0) ? ENOMEM : EINVAL;
+ *data_out = data;
+ *len_out = len;
+ return 0;
}
/*** Number type ***/
K5_JSON_TID_NUMBER, "number", NULL
};
-k5_json_number
-k5_json_number_create(long long number)
+int
+k5_json_number_create(long long number, k5_json_number *val_out)
{
k5_json_number n;
+ *val_out = NULL;
n = alloc_value(&number_type, sizeof(long long));
- if (n)
- *((long long *)n) = number;
- return n;
+ if (n == NULL)
+ return ENOMEM;
+ *((long long *)n) = number;
+ *val_out = n;
+ return 0;
}
long long
static const char needs_quote[] = "\\\"\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17"
"\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37";
-struct encode_ctx {
- struct k5buf buf;
- int ret;
- int first;
-};
-
-static int encode_value(struct encode_ctx *j, k5_json_value val);
+static int encode_value(struct k5buf *buf, k5_json_value val);
static void
-encode_string(struct encode_ctx *j, const char *str)
+encode_string(struct k5buf *buf, const char *str)
{
size_t n;
const char *p;
- krb5int_buf_add(&j->buf, "\"");
+ krb5int_buf_add(buf, "\"");
while (*str != '\0') {
n = strcspn(str, needs_quote);
- krb5int_buf_add_len(&j->buf, str, n);
+ krb5int_buf_add_len(buf, str, n);
str += n;
if (*str == '\0')
break;
- krb5int_buf_add(&j->buf, "\\");
+ krb5int_buf_add(buf, "\\");
p = strchr(quotemap_c, *str);
if (p != NULL)
- krb5int_buf_add_len(&j->buf, quotemap_json + (p - quotemap_c), 1);
+ krb5int_buf_add_len(buf, quotemap_json + (p - quotemap_c), 1);
else
- krb5int_buf_add_fmt(&j->buf, "u00%02X", (unsigned int)*str);
+ krb5int_buf_add_fmt(buf, "u00%02X", (unsigned int)*str);
str++;
}
- krb5int_buf_add(&j->buf, "\"");
+ krb5int_buf_add(buf, "\"");
}
+struct obj_ctx {
+ struct k5buf *buf;
+ int ret;
+ int first;
+};
+
static void
-encode_dict_entry(void *ctx, const char *key, k5_json_value value)
+encode_obj_entry(void *ctx, const char *key, k5_json_value value)
{
- struct encode_ctx *j = ctx;
+ struct obj_ctx *j = ctx;
if (j->ret)
return;
if (j->first)
j->first = 0;
else
- krb5int_buf_add(&j->buf, ",");
- encode_string(j, key);
- krb5int_buf_add(&j->buf, ":");
- j->ret = encode_value(j, value);
- if (j->ret)
- return;
+ krb5int_buf_add(j->buf, ",");
+ encode_string(j->buf, key);
+ krb5int_buf_add(j->buf, ":");
+ j->ret = encode_value(j->buf, value);
}
static int
-encode_value(struct encode_ctx *j, k5_json_value val)
+encode_value(struct k5buf *buf, k5_json_value val)
{
k5_json_tid type;
- int first = 0, ret;
+ int ret;
size_t i, len;
+ struct obj_ctx ctx;
if (val == NULL)
return EINVAL;
type = k5_json_get_tid(val);
switch (type) {
case K5_JSON_TID_ARRAY:
- krb5int_buf_add(&j->buf, "[");
+ krb5int_buf_add(buf, "[");
len = k5_json_array_length(val);
for (i = 0; i < len; i++) {
if (i != 0)
- krb5int_buf_add(&j->buf, ",");
- ret = encode_value(j, k5_json_array_get(val, i));
+ krb5int_buf_add(buf, ",");
+ ret = encode_value(buf, k5_json_array_get(val, i));
if (ret)
return ret;
}
- krb5int_buf_add(&j->buf, "]");
- break;
+ krb5int_buf_add(buf, "]");
+ return 0;
case K5_JSON_TID_OBJECT:
- krb5int_buf_add(&j->buf, "{");
- first = j->first;
- j->first = 1;
- k5_json_object_iterate(val, encode_dict_entry, j);
- krb5int_buf_add(&j->buf, "}");
- j->first = first;
- break;
+ krb5int_buf_add(buf, "{");
+ ctx.buf = buf;
+ ctx.ret = 0;
+ ctx.first = 1;
+ k5_json_object_iterate(val, encode_obj_entry, &ctx);
+ krb5int_buf_add(buf, "}");
+ return ctx.ret;
case K5_JSON_TID_STRING:
- encode_string(j, k5_json_string_utf8(val));
- break;
+ encode_string(buf, k5_json_string_utf8(val));
+ return 0;
case K5_JSON_TID_NUMBER:
- krb5int_buf_add_fmt(&j->buf, "%lld", k5_json_number_value(val));
- break;
+ krb5int_buf_add_fmt(buf, "%lld", k5_json_number_value(val));
+ return 0;
case K5_JSON_TID_NULL:
- krb5int_buf_add(&j->buf, "null");
- break;
+ krb5int_buf_add(buf, "null");
+ return 0;
case K5_JSON_TID_BOOL:
- krb5int_buf_add(&j->buf, k5_json_bool_value(val) ? "true" : "false");
- break;
+ krb5int_buf_add(buf, k5_json_bool_value(val) ? "true" : "false");
+ return 0;
default:
- return 1;
+ return EINVAL;
}
- return 0;
}
-char *
-k5_json_encode(k5_json_value val)
+int
+k5_json_encode(k5_json_value val, char **json_out)
{
- struct encode_ctx j;
+ struct k5buf buf;
+ int ret;
- j.ret = 0;
- j.first = 1;
- krb5int_buf_init_dynamic(&j.buf);
- if (encode_value(&j, val)) {
- krb5int_free_buf(&j.buf);
- return NULL;
+ *json_out = NULL;
+ krb5int_buf_init_dynamic(&buf);
+ ret = encode_value(&buf, val);
+ if (ret) {
+ krb5int_free_buf(&buf);
+ return ret;
}
- return krb5int_buf_data(&j.buf);
+ *json_out = krb5int_buf_data(&buf);
+ return (*json_out == NULL) ? ENOMEM : 0;
}
/*** JSON decoding ***/
size_t depth;
};
-static k5_json_value
-parse_value(struct decode_ctx *ctx);
+static int parse_value(struct decode_ctx *ctx, k5_json_value *val_out);
/* Consume whitespace. Return 0 if there is anything left to parse after the
* whitespace, -1 if not. */
/* Parse a JSON number (which must be an integer in the signed 64-bit range; we
* do not allow floating-point numbers). */
-static k5_json_number
-parse_number(struct decode_ctx *ctx)
+static int
+parse_number(struct decode_ctx *ctx, k5_json_number *val_out)
{
const unsigned long long umax = ~0ULL, smax = (1ULL << 63) - 1;
unsigned long long number = 0;
int neg = 1;
+ *val_out = NULL;
+
if (*ctx->p == '-') {
neg = -1;
ctx->p++;
}
if (!is_digit(*ctx->p))
- return NULL;
+ return EINVAL;
/* Read the number into an unsigned 64-bit container, ensuring that we
* don't overflow it. */
while (is_digit(*ctx->p)) {
if (number + 1 > umax / 10)
- return NULL;
+ return EOVERFLOW;
number = (number * 10) + (*ctx->p - '0');
ctx->p++;
}
/* Make sure the unsigned 64-bit value fits in the signed 64-bit range. */
if (number > smax + 1 || (number > smax && neg == 1))
- return NULL;
+ return EOVERFLOW;
- return k5_json_number_create(number * neg);
+ return k5_json_number_create(number * neg, val_out);
}
/* Parse a JSON string (which must not quote Unicode code points above 256). */
-static char *
-parse_string(struct decode_ctx *ctx)
+static int
+parse_string(struct decode_ctx *ctx, char **str_out)
{
const unsigned char *p, *start, *end = NULL;
const char *q;
char *buf, *pos;
unsigned int code;
+ *str_out = NULL;
+
/* Find the start and end of the string. */
if (*ctx->p != '"')
- return NULL;
+ return EINVAL;
start = ++ctx->p;
for (; *ctx->p != '\0'; ctx->p++) {
if (*ctx->p == '\\') {
ctx->p++;
if (*ctx->p == '\0')
- return NULL;
+ return EINVAL;
} else if (*ctx->p == '"') {
end = ctx->p++;
break;
}
}
if (end == NULL)
- return NULL;
+ return EINVAL;
pos = buf = malloc(end - start + 1);
if (buf == NULL)
- return NULL;
+ return ENOMEM;
for (p = start; p < end;) {
if (*p == '\\') {
p++;
/* Code points above 0xff don't need to be quoted, so we
* don't implement translating those into UTF-8. */
free(buf);
- return NULL;
+ return EINVAL;
}
p += 5;
} else {
*pos++ = quotemap_c[q - quotemap_json];
} else {
free(buf);
- return NULL;
+ return EINVAL;
}
p++;
}
}
}
*pos = '\0';
- return buf;
+ *str_out = buf;
+ return 0;
}
-/*
- * Parse an object association and the following comma. Return 1 if an
- * association was parsed, 0 if the end of the object was reached, and -1 on
- * error.
- */
+/* Parse an object association and place it into obj. */
static int
-parse_pair(k5_json_object obj, struct decode_ctx *ctx)
+parse_object_association(k5_json_object obj, struct decode_ctx *ctx)
{
char *key = NULL;
- k5_json_value value;
-
- if (white_spaces(ctx))
- goto err;
-
- /* Check for the end of the object. */
- if (*ctx->p == '}') {
- ctx->p++;
- return 0;
- }
+ k5_json_value val;
+ int ret;
/* Parse the key and value. */
- key = parse_string(ctx);
- if (key == NULL)
- goto err;
+ ret = parse_string(ctx, &key);
+ if (ret)
+ return ret;
if (white_spaces(ctx))
- goto err;
+ goto invalid;
if (*ctx->p != ':')
- goto err;
+ goto invalid;
ctx->p++;
if (white_spaces(ctx))
- goto err;
- value = parse_value(ctx);
- if (value == NULL) {
+ goto invalid;
+ ret = parse_value(ctx, &val);
+ if (ret) {
free(key);
- return -1;
+ return ret;
}
- /* Add the key and value to the object. */
- k5_json_object_set(obj, key, value);
+ /* Add the key and value to obj. */
+ ret = k5_json_object_set(obj, key, val);
free(key);
- key = NULL;
- k5_json_release(value);
-
- /* Consume the following comma if this isn't the last item. */
- if (white_spaces(ctx))
- goto err;
- if (*ctx->p == ',')
- ctx->p++;
- else if (*ctx->p != '}')
- goto err;
+ k5_json_release(val);
+ return ret;
- return 1;
-
-err:
+invalid:
free(key);
- return -1;
+ return EINVAL;
}
/* Parse a JSON object. */
-static k5_json_object
-parse_object(struct decode_ctx *ctx)
+static int
+parse_object(struct decode_ctx *ctx, k5_json_object *val_out)
{
- k5_json_object obj;
+ k5_json_object obj = NULL;
int ret;
- obj = k5_json_object_create();
- if (obj == NULL)
- return NULL;
+ *val_out = NULL;
+ /* Parse past the opening brace. */
+ if (*ctx->p != '{')
+ return EINVAL;
ctx->p++;
- while ((ret = parse_pair(obj, ctx)) > 0)
- ;
- if (ret < 0) {
- k5_json_release(obj);
- return NULL;
- }
- return obj;
-}
-
-/* Parse a JSON array item and the following comma. Return 1 if an item was
- * parsed, 0 if the end of the array was reached, and -1 on error. */
-static int
-parse_item(k5_json_array array, struct decode_ctx *ctx)
-{
- k5_json_value value;
-
if (white_spaces(ctx))
- return -1;
+ return EINVAL;
- if (*ctx->p == ']') {
- ctx->p++;
- return 0;
- }
+ ret = k5_json_object_create(&obj);
+ if (ret)
+ return ret;
- value = parse_value(ctx);
- if (value == NULL)
- return -1;
+ /* Pairs associations until we reach the terminating brace. */
+ if (*ctx->p != '}') {
+ while (1) {
+ ret = parse_object_association(obj, ctx);
+ if (ret) {
+ k5_json_release(obj);
+ return ret;
+ }
+ if (white_spaces(ctx))
+ goto invalid;
+ if (*ctx->p == '}')
+ break;
+ if (*ctx->p != ',')
+ goto invalid;
+ ctx->p++;
+ if (white_spaces(ctx))
+ goto invalid;
+ }
+ }
+ ctx->p++;
+ *val_out = obj;
+ return 0;
- k5_json_array_add(array, value);
- k5_json_release(value);
+invalid:
+ k5_json_release(obj);
+ return EINVAL;
+}
- if (white_spaces(ctx))
- return -1;
+/* Parse an value and place it into array. */
+static int
+parse_array_item(k5_json_array array, struct decode_ctx *ctx)
+{
+ k5_json_value val;
+ int ret;
- if (*ctx->p == ',')
- ctx->p++;
- else if (*ctx->p != ']')
- return -1;
- return 1;
+ ret = parse_value(ctx, &val);
+ if (ret)
+ return ret;
+ ret = k5_json_array_add(array, val);
+ k5_json_release(val);
+ return ret;
}
/* Parse a JSON array. */
-static k5_json_array
-parse_array(struct decode_ctx *ctx)
+static int
+parse_array(struct decode_ctx *ctx, k5_json_array *val_out)
{
- k5_json_array array = k5_json_array_create();
+ k5_json_array array = NULL;
int ret;
- assert(*ctx->p == '[');
- ctx->p += 1;
+ *val_out = NULL;
- while ((ret = parse_item(array, ctx)) > 0)
- ;
- if (ret < 0) {
- k5_json_release(array);
- return NULL;
+ /* Parse past the opening bracket. */
+ if (*ctx->p != '[')
+ return EINVAL;
+ ctx->p++;
+ if (white_spaces(ctx))
+ return EINVAL;
+
+ ret = k5_json_array_create(&array);
+ if (ret)
+ return ret;
+
+ /* Pairs values until we reach the terminating bracket. */
+ if (*ctx->p != ']') {
+ while (1) {
+ ret = parse_array_item(array, ctx);
+ if (ret) {
+ k5_json_release(array);
+ return ret;
+ }
+ if (white_spaces(ctx))
+ goto invalid;
+ if (*ctx->p == ']')
+ break;
+ if (*ctx->p != ',')
+ goto invalid;
+ ctx->p++;
+ if (white_spaces(ctx))
+ goto invalid;
+ }
}
- return array;
+ ctx->p++;
+ *val_out = array;
+ return 0;
+
+invalid:
+ k5_json_release(array);
+ return EINVAL;
}
/* Parse a JSON value of any type. */
-static k5_json_value
-parse_value(struct decode_ctx *ctx)
+static int
+parse_value(struct decode_ctx *ctx, k5_json_value *val_out)
{
- k5_json_value v;
- char *str;
+ k5_json_null null;
+ k5_json_bool bval;
+ k5_json_number num;
+ k5_json_string str;
+ k5_json_object obj;
+ k5_json_array array;
+ char *cstring;
+ int ret;
+
+ *val_out = NULL;
if (white_spaces(ctx))
- return NULL;
+ return EINVAL;
if (*ctx->p == '"') {
- str = parse_string(ctx);
- if (str == NULL)
- return NULL;
- v = k5_json_string_create(str);
- free(str);
- return v;
+ ret = parse_string(ctx, &cstring);
+ if (ret)
+ return ret;
+ ret = k5_json_string_create(cstring, &str);
+ free(cstring);
+ if (ret)
+ return ret;
+ *val_out = str;
} else if (*ctx->p == '{') {
if (ctx->depth-- == 1)
- return NULL;
- v = parse_object(ctx);
+ return EINVAL;
+ ret = parse_object(ctx, &obj);
+ if (ret)
+ return ret;
ctx->depth++;
- return v;
+ *val_out = obj;
} else if (*ctx->p == '[') {
if (ctx->depth-- == 1)
- return NULL;
- v = parse_array(ctx);
+ return EINVAL;
+ ret = parse_array(ctx, &array);
ctx->depth++;
- return v;
+ *val_out = array;
} else if (is_digit(*ctx->p) || *ctx->p == '-') {
- return parse_number(ctx);
- }
-
- if (strncmp((char *)ctx->p, "null", 4) == 0) {
+ ret = parse_number(ctx, &num);
+ if (ret)
+ return ret;
+ *val_out = num;
+ } else if (strncmp((char *)ctx->p, "null", 4) == 0) {
ctx->p += 4;
- return k5_json_null_create();
+ ret = k5_json_null_create(&null);
+ if (ret)
+ return ret;
+ *val_out = null;
} else if (strncmp((char *)ctx->p, "true", 4) == 0) {
ctx->p += 4;
- return k5_json_bool_create(1);
+ ret = k5_json_bool_create(1, &bval);
+ if (ret)
+ return ret;
+ *val_out = bval;
} else if (strncmp((char *)ctx->p, "false", 5) == 0) {
ctx->p += 5;
- return k5_json_bool_create(0);
+ ret = k5_json_bool_create(0, &bval);
+ if (ret)
+ return ret;
+ *val_out = bval;
+ } else {
+ return EINVAL;
}
- return NULL;
+ return 0;
}
-k5_json_value
-k5_json_decode(const char *string)
+int
+k5_json_decode(const char *string, k5_json_value *val_out)
{
struct decode_ctx ctx;
- k5_json_value v;
+ k5_json_value val;
+ int ret;
+ *val_out = NULL;
ctx.p = (unsigned char *)string;
ctx.depth = MAX_DECODE_DEPTH;
- v = parse_value(&ctx);
+ ret = parse_value(&ctx, &val);
+ if (ret)
+ return ret;
if (white_spaces(&ctx) == 0) {
- k5_json_release(v);
- return NULL;
+ k5_json_release(val);
+ return EINVAL;
}
- return v;
+ *val_out = val;
+ return 0;
}
static void
test_array()
{
- k5_json_string v1 = k5_json_string_create("abc");
- k5_json_number v2 = k5_json_number_create(2);
- k5_json_null v3 = k5_json_null_create();
- k5_json_array a = k5_json_array_create();
+ k5_json_string v1;
+ k5_json_number v2;
+ k5_json_null v3;
+ k5_json_array a;
k5_json_value v;
+ k5_json_array_create(&a);
+ k5_json_string_create("abc", &v1);
k5_json_array_add(a, v1);
+ k5_json_number_create(2, &v2);
k5_json_array_add(a, v2);
+ k5_json_null_create(&v3);
k5_json_array_add(a, v3);
check(k5_json_array_length(a) == 3, "array length");
test_object(void)
{
k5_json_object object;
- k5_json_number n, v1 = k5_json_number_create(1);
- k5_json_string s, v2 = k5_json_string_create("hejsan");
+ k5_json_number n, v1;
+ k5_json_string s, v2;
- object = k5_json_object_create();
+ k5_json_object_create(&object);
+ k5_json_number_create(1, &v1);
k5_json_object_set(object, "key1", v1);
+ k5_json_string_create("hejsan", &v2);
k5_json_object_set(object, "key2", v2);
n = k5_json_object_get(object, "key1");
test_string(void)
{
k5_json_string s1, s2, s3;
- void *data;
+ unsigned char *data;
size_t len;
- s1 = k5_json_string_create("hejsan");
- s2 = k5_json_string_create("hejsan");
- s3 = k5_json_string_create_base64("55555", 5);
+ k5_json_string_create("hejsan", &s1);
+ k5_json_string_create("hejsan", &s2);
+ k5_json_string_create_base64("55555", 5, &s3);
if (strcmp(k5_json_string_utf8(s1), k5_json_string_utf8(s2)) != 0)
err("Identical strings are not identical");
if (strcmp(k5_json_string_utf8(s3), "NTU1NTU=") != 0)
err("base64 string has incorrect value");
- data = k5_json_string_unbase64(s3, &len);
- if (data == NULL || len != 5 || memcmp(data, "55555", 5) != 0)
+ k5_json_string_unbase64(s3, &data, &len);
+ if (len != 5 || memcmp(data, "55555", 5) != 0)
err("base64 string doesn't decode to correct value");
+ free(data);
k5_json_release(s1);
k5_json_release(s2);
int i;
k5_json_value v, v2;
- v = k5_json_decode("\"string\"");
- check(v != NULL, "string1");
+ check(k5_json_decode("\"string\"", &v) == 0, "string1");
check(k5_json_get_tid(v) == K5_JSON_TID_STRING, "string1 tid");
check(strcmp(k5_json_string_utf8(v), "string") == 0, "string1 utf8");
k5_json_release(v);
- v = k5_json_decode("\t \"foo\\\"bar\" ");
- check(v != NULL, "string2");
+ check(k5_json_decode("\t \"foo\\\"bar\" ", &v) == 0, "string2");
check(k5_json_get_tid(v) == K5_JSON_TID_STRING, "string2 tid");
check(strcmp(k5_json_string_utf8(v), "foo\"bar") == 0, "string2 utf8");
k5_json_release(v);
- v = k5_json_decode(" { \"key\" : \"value\" }");
- check(v != NULL, "object1");
+ check(k5_json_decode(" { \"key\" : \"value\" }", &v) == 0, "object1");
check(k5_json_get_tid(v) == K5_JSON_TID_OBJECT, "object1 tid");
v2 = k5_json_object_get(v, "key");
check(v2 != NULL, "object[key]");
check(strcmp(k5_json_string_utf8(v2), "value") == 0, "object1[key] utf8");
k5_json_release(v);
- v = k5_json_decode("{ \"k1\" : { \"k2\" : \"s2\", \"k3\" : \"s3\" }, "
- "\"k4\" : \"s4\" }");
- check(v != NULL, "object2");
+ check(k5_json_decode("{ \"k1\" : { \"k2\" : \"s2\", \"k3\" : \"s3\" }, "
+ "\"k4\" : \"s4\" }", &v) == 0, "object2");
v2 = k5_json_object_get(v, "k1");
check(v2 != NULL, "object2[k1]");
check(k5_json_get_tid(v2) == K5_JSON_TID_OBJECT, "object2[k1] tid");
check(strcmp(k5_json_string_utf8(v2), "s3") == 0, "object2[k1][k3] utf8");
k5_json_release(v);
- v = k5_json_decode("{ \"k1\" : 1 }");
- check(v != NULL, "object3");
+ check(k5_json_decode("{ \"k1\" : 1 }", &v) == 0, "object3");
check(k5_json_get_tid(v) == K5_JSON_TID_OBJECT, "object3 id");
v2 = k5_json_object_get(v, "k1");
check(k5_json_get_tid(v2) == K5_JSON_TID_NUMBER, "object3[k1] tid");
check(k5_json_number_value(v2) == 1, "object3[k1] value");
k5_json_release(v);
- v = k5_json_decode("-10");
- check(v != NULL, "number1");
+ check(k5_json_decode("-10", &v) == 0, "number1");
check(k5_json_get_tid(v) == K5_JSON_TID_NUMBER, "number1 tid");
check(k5_json_number_value(v) == -10, "number1 value");
k5_json_release(v);
- v = k5_json_decode("99");
- check(v != NULL, "number2");
+ check(k5_json_decode("99", &v) == 0, "number2");
check(k5_json_get_tid(v) == K5_JSON_TID_NUMBER, "number2 tid");
check(k5_json_number_value(v) == 99, "number2 value");
k5_json_release(v);
- v = k5_json_decode(" [ 1 ]");
- check(v != NULL, "array1");
+ check(k5_json_decode(" [ 1 ]", &v) == 0, "array1");
check(k5_json_get_tid(v) == K5_JSON_TID_ARRAY, "array1 tid");
check(k5_json_array_length(v) == 1, "array1 len");
v2 = k5_json_array_get(v, 0);
check(k5_json_number_value(v2) == 1, "array1[0] value");
k5_json_release(v);
- v = k5_json_decode(" [ -1 ]");
- check(v != NULL, "array2");
+ check(k5_json_decode(" [ -1 ]", &v) == 0, "array2");
check(k5_json_get_tid(v) == K5_JSON_TID_ARRAY, "array2 tid");
check(k5_json_array_length(v) == 1, "array2 len");
v2 = k5_json_array_get(v, 0);
check(k5_json_number_value(v2) == -1, "array2[0] value");
k5_json_release(v);
- v = k5_json_decode("18446744073709551616");
- check(v == NULL, "unsigned 64-bit overflow");
- v = k5_json_decode("9223372036854775808");
- check(v == NULL, "signed 64-bit positive overflow");
- v = k5_json_decode("-9223372036854775809");
- check(v == NULL, "signed 64-bit negative overflow");
+ check(k5_json_decode("18446744073709551616", &v) == EOVERFLOW,
+ "unsigned 64-bit overflow");
+ check(k5_json_decode("9223372036854775808", &v) == EOVERFLOW,
+ "signed 64-bit positive overflow");
+ check(k5_json_decode("-9223372036854775809", &v) == EOVERFLOW,
+ "signed 64-bit negative overflow");
for (tptr = tests; *tptr != NULL; tptr++) {
s = strdup(*tptr);
- v = k5_json_decode(s);
- if (v == NULL)
+ if (k5_json_decode(s, &v))
err(s);
- enc = k5_json_encode(v);
- if (enc == NULL || strcmp(enc, s) != 0)
+ if (k5_json_encode(v, &enc) || strcmp(enc, s) != 0)
err(s);
free(enc);
k5_json_release(v);
orig = *p;
for (i = 0; i <= 255; i++) {
*p = i;
- k5_json_release(k5_json_decode(s));
+ k5_json_decode(s, &v);
+ k5_json_release(v);
}
*p = orig;
}