diff options
-rw-r--r-- | src/include/k5-json.h | 18 | ||||
-rw-r--r-- | src/lib/gssapi/krb5/export_cred.c | 534 | ||||
-rw-r--r-- | src/util/support/json.c | 93 | ||||
-rw-r--r-- | src/util/support/libkrb5support-fixed.exports | 2 | ||||
-rw-r--r-- | src/util/support/t_json.c | 26 |
5 files changed, 412 insertions, 261 deletions
diff --git a/src/include/k5-json.h b/src/include/k5-json.h index 4b9b8fec3b..b01b8b847e 100644 --- a/src/include/k5-json.h +++ b/src/include/k5-json.h @@ -109,6 +109,9 @@ typedef struct k5_json_null_st *k5_json_null; int k5_json_null_create(k5_json_null *null_out); +/* Create a null value as a k5_json_value, for polymorphic convenience. */ +int k5_json_null_create_val(k5_json_value *val_out); + /* * Boolean */ @@ -136,6 +139,21 @@ void k5_json_array_set(k5_json_array array, size_t idx, k5_json_value val); k5_json_value k5_json_array_get(k5_json_array array, size_t idx); /* + * Create an array from a template and a variable argument list. template + * characters are: + * v: a k5_json_value argument is read, retained, and stored + * n: no argument is read; a null value is stored + * b: an int argument is read and stored as a boolean value + * i: an int argument is read and stored as a number value + * L: a long long argument is read and stored as a number value + * s: a const char * argument is read and stored as a null or string value + * B: const void * and size_t arguments are read and stored as a base64 + * string value + */ +int +k5_json_array_fmt(k5_json_array *array_out, const char *template, ...); + +/* * Object */ diff --git a/src/lib/gssapi/krb5/export_cred.c b/src/lib/gssapi/krb5/export_cred.c index e5ffaf54aa..652b2604bd 100644 --- a/src/lib/gssapi/krb5/export_cred.c +++ b/src/lib/gssapi/krb5/export_cred.c @@ -34,387 +34,400 @@ #include "k5-json.h" #include "gssapiP_krb5.h" -/* Add v to array and then release it. Return -1 if v is NULL. */ -static int -add(k5_json_array array, k5_json_value v) -{ - if (v == NULL || k5_json_array_add(array, v)) - return -1; - k5_json_release(v); - 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)null() : string(str); -} - /* Return a JSON null or array value representing princ. */ -static k5_json_value -json_principal(krb5_context context, krb5_principal princ) +static krb5_error_code +json_principal(krb5_context context, krb5_principal princ, + k5_json_value *val_out) { + krb5_error_code ret; + k5_json_string str = NULL; char *princname; - k5_json_string str; + *val_out = NULL; if (princ == NULL) - return null(); - if (krb5_unparse_name(context, princ, &princname)) - return NULL; - str = string(princname); + return k5_json_null_create_val(val_out); + ret = krb5_unparse_name(context, princ, &princname); + if (ret) + return ret; + ret = k5_json_string_create(princname, &str); krb5_free_unparsed_name(context, princname); - return str; + *val_out = str; + return ret; } /* Return a json null or array value representing etypes. */ -static k5_json_value -json_etypes(krb5_enctype *etypes) +static krb5_error_code +json_etypes(krb5_enctype *etypes, k5_json_value *val_out) { + krb5_error_code ret; + k5_json_number num; k5_json_array array; + *val_out = NULL; if (etypes == NULL) - return null(); - if (k5_json_array_create(&array)) - return NULL; + return k5_json_null_create_val(val_out); + ret = k5_json_array_create(&array); + if (ret) + return ret; for (; *etypes != 0; etypes++) { - if (add(array, number(*etypes))) - goto oom; + ret = k5_json_number_create(*etypes, &num); + if (ret) + goto err; + ret = k5_json_array_add(array, num); + k5_json_release(num); + if (ret) + goto err; } - return array; -oom: + *val_out = array; + return 0; +err: k5_json_release(array); - return NULL; + return ret; } /* Return a JSON null or array value representing name. */ -static k5_json_value -json_kgname(krb5_context context, krb5_gss_name_t name) +static krb5_error_code +json_kgname(krb5_context context, krb5_gss_name_t name, k5_json_value *val_out) { - k5_json_array array; + krb5_error_code ret; + k5_json_array array = NULL; + k5_json_value princ; + *val_out = NULL; if (name == NULL) - return null(); - if (k5_json_array_create(&array)) - return NULL; - if (add(array, json_principal(context, name->princ))) - goto oom; - if (add(array, json_optional_string(name->service))) - goto oom; - if (add(array, json_optional_string(name->host))) - goto oom; - return array; -oom: - k5_json_release(array); - return NULL; + return k5_json_null_create_val(val_out); + ret = json_principal(context, name->princ, &princ); + if (ret) + return ret; + ret = k5_json_array_fmt(&array, "vss", princ, name->service, name->host); + k5_json_release(princ); + *val_out = array; + return ret; } /* Return a JSON null or string value representing keytab. */ -static k5_json_value -json_keytab(krb5_context context, krb5_keytab keytab) +static krb5_error_code +json_keytab(krb5_context context, krb5_keytab keytab, k5_json_value *val_out) { + krb5_error_code ret; + k5_json_string str; char name[1024]; + *val_out = NULL; if (keytab == NULL) - return null(); - if (krb5_kt_get_name(context, keytab, name, sizeof(name))) - return NULL; - return string(name); + return k5_json_null_create_val(val_out); + ret = krb5_kt_get_name(context, keytab, name, sizeof(name)); + if (ret) + return ret; + ret = k5_json_string_create(name, &str); + *val_out = str; + return ret; } /* Return a JSON null or string value representing rcache. */ -static k5_json_value -json_rcache(krb5_context context, krb5_rcache rcache) +static krb5_error_code +json_rcache(krb5_context context, krb5_rcache rcache, k5_json_value *val_out) { + krb5_error_code ret; + k5_json_string str = NULL; char *name; - k5_json_string str; if (rcache == NULL) - return null(); + return k5_json_null_create_val(val_out); if (asprintf(&name, "%s:%s", krb5_rc_get_type(context, rcache), krb5_rc_get_name(context, rcache)) < 0) - return NULL; - str = string(name); + return ENOMEM; + ret = k5_json_string_create(name, &str); free(name); - return str; + *val_out = str; + return ret; } /* Return a JSON array value representing keyblock. */ -static k5_json_value -json_keyblock(krb5_keyblock *keyblock) +static krb5_error_code +json_keyblock(krb5_keyblock *kb, k5_json_value *val_out) { + krb5_error_code ret; k5_json_array array; - if (k5_json_array_create(&array)) - return NULL; - if (add(array, number(keyblock->enctype))) - goto oom; - if (add(array, base64string(keyblock->contents, keyblock->length))) - goto oom; - return array; -oom: - k5_json_release(array); - return NULL; + *val_out = NULL; + ret = k5_json_array_fmt(&array, "iB", kb->enctype, (void *)kb->contents, + (size_t)kb->length); + if (ret) + return ret; + *val_out = array; + return 0; } /* Return a JSON array value representing addr. */ -static k5_json_value -json_address(krb5_address *addr) +static krb5_error_code +json_address(krb5_address *addr, k5_json_value *val_out) { + krb5_error_code ret; k5_json_array array; - if (k5_json_array_create(&array)) - return NULL; - if (add(array, number(addr->addrtype))) - goto oom; - if (add(array, base64string(addr->contents, addr->length))) - goto oom; - return array; -oom: - k5_json_release(array); - return NULL; + *val_out = NULL; + ret = k5_json_array_fmt(&array, "iB", addr->addrtype, + (void *)addr->contents, (size_t)addr->length); + if (ret) + return ret; + *val_out = array; + return 0; } /* Return a JSON null or array value representing addrs. */ -static k5_json_value -json_addresses(krb5_address **addrs) +static krb5_error_code +json_addresses(krb5_address **addrs, k5_json_value *val_out) { + krb5_error_code ret; k5_json_array array; + k5_json_value val; + *val_out = NULL; if (addrs == NULL) - return null(); - if (k5_json_array_create(&array)) - return NULL; + return k5_json_null_create_val(val_out); + ret = k5_json_array_create(&array); + if (ret) + return ret; for (; *addrs != NULL; addrs++) { - if (add(array, json_address(*addrs))) { - k5_json_release(array); - return NULL; - } + ret = json_address(*addrs, &val); + if (ret) + goto err; + ret = k5_json_array_add(array, val); + k5_json_release(val); + if (ret) + goto err; } - return array; + *val_out = array; + return 0; +err: + k5_json_release(array); + return ret; } /* Return a JSON array value representing ad. */ -static k5_json_value -json_authdata_element(krb5_authdata *ad) +static krb5_error_code +json_authdata_element(krb5_authdata *ad, k5_json_value *val_out) { + krb5_error_code ret; k5_json_array array; - if (k5_json_array_create(&array)) - return NULL; - if (add(array, number(ad->ad_type))) - goto oom; - if (add(array, base64string(ad->contents, ad->length))) - goto oom; - return array; -oom: - k5_json_release(array); - return NULL; + *val_out = NULL; + ret = k5_json_array_fmt(&array, "iB", ad->ad_type, (void *)ad->contents, + (size_t)ad->length); + if (ret) + return ret; + *val_out = array; + return 0; } /* Return a JSON null or array value representing authdata. */ -static k5_json_value -json_authdata(krb5_authdata **authdata) +static krb5_error_code +json_authdata(krb5_authdata **authdata, k5_json_value *val_out) { + krb5_error_code ret; k5_json_array array; + k5_json_value val; + *val_out = NULL; if (authdata == NULL) - return null(); - if (k5_json_array_create(&array)) - return NULL; + return k5_json_null_create_val(val_out); + ret = k5_json_array_create(&array); + if (ret) + return ret; for (; *authdata != NULL; authdata++) { - if (add(array, json_authdata_element(*authdata))) { - k5_json_release(array); - return NULL; - } + ret = json_authdata_element(*authdata, &val); + if (ret) + goto err; + ret = k5_json_array_add(array, val); + k5_json_release(val); + if (ret) + goto err; } - return array; + *val_out = array; + return 0; +err: + k5_json_release(array); + return ret; } /* Return a JSON array value representing creds. */ -static k5_json_value -json_creds(krb5_context context, krb5_creds *creds) +static krb5_error_code +json_creds(krb5_context context, krb5_creds *creds, k5_json_value *val_out) { + krb5_error_code ret; k5_json_array array; + k5_json_value client = NULL, server = NULL, keyblock = NULL, addrs = NULL; + k5_json_value authdata = NULL; + + *val_out = NULL; + ret = json_principal(context, creds->client, &client); + if (ret) + goto cleanup; + ret = json_principal(context, creds->server, &server); + if (ret) + goto cleanup; + ret = json_keyblock(&creds->keyblock, &keyblock); + if (ret) + goto cleanup; + ret = json_addresses(creds->addresses, &addrs); + if (ret) + goto cleanup; + ret = json_authdata(creds->authdata, &authdata); + if (ret) + goto cleanup; + + ret = k5_json_array_fmt(&array, "vvviiiibivBBv", client, server, keyblock, + creds->times.authtime, creds->times.starttime, + creds->times.endtime, creds->times.renew_till, + creds->is_skey, creds->ticket_flags, addrs, + (void *)creds->ticket.data, + (size_t)creds->ticket.length, + (void *)creds->second_ticket.data, + (size_t)creds->second_ticket.length, authdata); + if (ret) + goto cleanup; + *val_out = array; - if (k5_json_array_create(&array)) - return NULL; - if (add(array, json_principal(context, creds->client))) - goto eom; - if (add(array, json_principal(context, creds->server))) - goto eom; - if (add(array, json_keyblock(&creds->keyblock))) - goto eom; - if (add(array, number(creds->times.authtime))) - goto eom; - if (add(array, number(creds->times.starttime))) - goto eom; - if (add(array, number(creds->times.endtime))) - goto eom; - if (add(array, number(creds->times.renew_till))) - goto eom; - if (add(array, bool(creds->is_skey))) - goto eom; - if (add(array, number(creds->ticket_flags))) - goto eom; - if (add(array, json_addresses(creds->addresses))) - goto eom; - if (add(array, base64string(creds->ticket.data, creds->ticket.length))) - goto eom; - if (add(array, base64string(creds->second_ticket.data, - creds->second_ticket.length))) - goto eom; - if (add(array, json_authdata(creds->authdata))) - goto eom; - return array; -eom: - k5_json_release(array); - return NULL; +cleanup: + k5_json_release(client); + k5_json_release(server); + k5_json_release(keyblock); + k5_json_release(addrs); + k5_json_release(authdata); + return ret; } /* Return a JSON array value representing the contents of ccache. */ -static k5_json_value -json_ccache_contents(krb5_context context, krb5_ccache ccache) +static krb5_error_code +json_ccache_contents(krb5_context context, krb5_ccache ccache, + k5_json_value *val_out) { krb5_error_code ret; krb5_principal princ; krb5_cc_cursor cursor; krb5_creds creds; k5_json_array array; - int st; + k5_json_value val; - if (k5_json_array_create(&array)) - return NULL; + *val_out = NULL; + ret = k5_json_array_create(&array); + if (ret) + return ret; /* Put the principal in the first array entry. */ - if (krb5_cc_get_principal(context, ccache, &princ)) + ret = krb5_cc_get_principal(context, ccache, &princ); + if (ret) goto err; - st = add(array, json_principal(context, princ)); + ret = json_principal(context, princ, &val); krb5_free_principal(context, princ); - if (st) + if (ret) + goto err; + ret = k5_json_array_add(array, val); + k5_json_release(val); + if (ret) goto err; /* Put credentials in the remaining array entries. */ - if (krb5_cc_start_seq_get(context, ccache, &cursor)) + ret = krb5_cc_start_seq_get(context, ccache, &cursor); + if (ret) goto err; while ((ret = krb5_cc_next_cred(context, ccache, &cursor, &creds)) == 0) { - if (add(array, json_creds(context, &creds))) { - krb5_free_cred_contents(context, &creds); - break; - } + ret = json_creds(context, &creds, &val); krb5_free_cred_contents(context, &creds); + if (ret) + break; + ret = k5_json_array_add(array, val); + k5_json_release(val); + if (ret) + break; } krb5_cc_end_seq_get(context, ccache, &cursor); if (ret != KRB5_CC_END) goto err; - return array; + *val_out = array; + return 0; err: k5_json_release(array); - return NULL; + return ret; } /* Return a JSON null, string, or array value representing ccache. */ -static k5_json_value -json_ccache(krb5_context context, krb5_ccache ccache) +static krb5_error_code +json_ccache(krb5_context context, krb5_ccache ccache, k5_json_value *val_out) { - char *name; + krb5_error_code ret; k5_json_string str; + char *name; + *val_out = NULL; if (ccache == NULL) - return null(); + return k5_json_null_create_val(val_out); if (strcmp(krb5_cc_get_type(context, ccache), "MEMORY") == 0) { - return json_ccache_contents(context, ccache); + return json_ccache_contents(context, ccache, val_out); } else { - if (krb5_cc_get_full_name(context, ccache, &name)) - return NULL; - str = string(name); + ret = krb5_cc_get_full_name(context, ccache, &name); + if (ret) + return ret; + ret = k5_json_string_create(name, &str); free(name); - return str; + *val_out = str; + return ret; } } /* Return a JSON array value representing cred. */ -static k5_json_value -json_kgcred(krb5_context context, krb5_gss_cred_id_t cred) +static krb5_error_code +json_kgcred(krb5_context context, krb5_gss_cred_id_t cred, + k5_json_value *val_out) { + krb5_error_code ret; k5_json_array array; + k5_json_value name = NULL, imp = NULL, keytab = NULL, rcache = NULL; + k5_json_value ccache = NULL, ckeytab = NULL, etypes = NULL; + + *val_out = NULL; + ret = json_kgname(context, cred->name, &name); + if (ret) + goto cleanup; + ret = json_principal(context, cred->impersonator, &imp); + if (ret) + goto cleanup; + ret = json_keytab(context, cred->keytab, &keytab); + if (ret) + goto cleanup; + ret = json_rcache(context, cred->rcache, &rcache); + if (ret) + goto cleanup; + ret = json_ccache(context, cred->ccache, &ccache); + if (ret) + goto cleanup; + ret = json_keytab(context, cred->client_keytab, &ckeytab); + if (ret) + goto cleanup; + ret = json_etypes(cred->req_enctypes, &etypes); + if (ret) + goto cleanup; + + ret = k5_json_array_fmt(&array, "ivvbbvvvvbiivs", cred->usage, name, imp, + cred->default_identity, cred->iakerb_mech, keytab, + rcache, ccache, ckeytab, cred->have_tgt, + cred->expire, cred->refresh_time, etypes, + cred->password); + if (ret) + goto cleanup; + *val_out = array; - if (k5_json_array_create(&array)) - return NULL; - 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, bool(cred->default_identity))) - goto oom; - 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_rcache(context, cred->rcache))) - goto oom; - if (add(array, json_ccache(context, cred->ccache))) - goto oom; - if (add(array, json_keytab(context, cred->client_keytab))) - goto oom; - if (add(array, bool(cred->have_tgt))) - goto oom; - if (add(array, number(cred->expire))) - goto oom; - if (add(array, number(cred->refresh_time))) - goto oom; - if (add(array, json_etypes(cred->req_enctypes))) - goto oom; - if (add(array, json_optional_string(cred->password))) - goto oom; - return array; -oom: - k5_json_release(array); - return NULL; +cleanup: + k5_json_release(name); + k5_json_release(imp); + k5_json_release(keytab); + k5_json_release(rcache); + k5_json_release(ccache); + k5_json_release(ckeytab); + k5_json_release(etypes); + return ret; } OM_uint32 KRB5_CALLCONV @@ -426,6 +439,7 @@ krb5_gss_export_cred(OM_uint32 *minor_status, gss_cred_id_t cred_handle, krb5_error_code ret; krb5_gss_cred_id_t cred; k5_json_array array = NULL; + k5_json_value jcred = NULL; char *str = NULL; krb5_data d; @@ -441,13 +455,10 @@ krb5_gss_export_cred(OM_uint32 *minor_status, gss_cred_id_t cred_handle, return status; cred = (krb5_gss_cred_id_t)cred_handle; - if (k5_json_array_create(&array)) - goto oom; - if (add(array, string(CRED_EXPORT_MAGIC))) + if (json_kgcred(context, cred, &jcred)) goto oom; - if (add(array, json_kgcred(context, cred))) + if (k5_json_array_fmt(&array, "sv", CRED_EXPORT_MAGIC, jcred)) goto oom; - if (k5_json_encode(array, &str)) goto oom; d = string2data(str); @@ -459,6 +470,7 @@ cleanup: free(str); k5_mutex_unlock(&cred->lock); k5_json_release(array); + k5_json_release(jcred); krb5_free_context(context); return status; diff --git a/src/util/support/json.c b/src/util/support/json.c index 5151b84159..e3edffd7cd 100644 --- a/src/util/support/json.c +++ b/src/util/support/json.c @@ -167,6 +167,13 @@ k5_json_null_create(k5_json_null *val_out) return (*val_out == NULL) ? ENOMEM : 0; } +int +k5_json_null_create_val(k5_json_value *val_out) +{ + *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 }; @@ -265,6 +272,92 @@ k5_json_array_set(k5_json_array array, size_t idx, k5_json_value val) array->values[idx] = k5_json_retain(val); } +int +k5_json_array_fmt(k5_json_array *array_out, const char *template, ...) +{ + const char *p; + va_list ap; + const char *cstring; + unsigned char *data; + size_t len; + long long nval; + k5_json_array array; + k5_json_value val; + k5_json_number num; + k5_json_string str; + k5_json_bool b; + k5_json_null null; + int truth, ret; + + *array_out = NULL; + if (k5_json_array_create(&array)) + return ENOMEM; + va_start(ap, template); + for (p = template; *p != '\0'; p++) { + switch (*p) { + case 'v': + val = k5_json_retain(va_arg(ap, k5_json_value)); + break; + case 'n': + if (k5_json_null_create(&null)) + goto err; + val = null; + break; + case 'b': + truth = va_arg(ap, int); + if (k5_json_bool_create(truth, &b)) + goto err; + val = b; + break; + case 'i': + nval = va_arg(ap, int); + if (k5_json_number_create(nval, &num)) + goto err; + val = num; + break; + case 'L': + nval = va_arg(ap, long long); + if (k5_json_number_create(nval, &num)) + goto err; + val = num; + break; + case 's': + cstring = va_arg(ap, const char *); + if (cstring == NULL) { + if (k5_json_null_create(&null)) + goto err; + val = null; + } else { + if (k5_json_string_create(cstring, &str)) + goto err; + val = str; + } + break; + case 'B': + data = va_arg(ap, unsigned char *); + len = va_arg(ap, size_t); + if (k5_json_string_create_base64(data, len, &str)) + goto err; + val = str; + break; + default: + goto err; + } + ret = k5_json_array_add(array, val); + k5_json_release(val); + if (ret) + goto err; + } + va_end(ap); + *array_out = array; + return 0; + +err: + va_end(ap); + k5_json_release(array); + return ENOMEM; +} + /*** Object type (string:value mapping) ***/ struct entry { diff --git a/src/util/support/libkrb5support-fixed.exports b/src/util/support/libkrb5support-fixed.exports index c813310885..41c8c6b7b6 100644 --- a/src/util/support/libkrb5support-fixed.exports +++ b/src/util/support/libkrb5support-fixed.exports @@ -8,6 +8,7 @@ k5_clear_error k5_set_error_info_callout_fn k5_json_array_add k5_json_array_create +k5_json_array_fmt k5_json_array_get k5_json_array_length k5_json_array_set @@ -17,6 +18,7 @@ k5_json_decode k5_json_encode k5_json_get_tid k5_json_null_create +k5_json_null_create_val k5_json_number_create k5_json_number_value k5_json_object_count diff --git a/src/util/support/t_json.c b/src/util/support/t_json.c index afb02ee614..040a85a914 100644 --- a/src/util/support/t_json.c +++ b/src/util/support/t_json.c @@ -114,6 +114,32 @@ test_array() k5_json_release(v1); k5_json_release(v2); + k5_json_release(a); + + k5_json_array_fmt(&a, "vnbiLssB", v3, 1, 9, (long long)-6, "def", NULL, + (void *)"ghij", (size_t)4); + v = k5_json_array_get(a, 0); + check(k5_json_get_tid(v) == K5_JSON_TID_NULL, "fmt array[0] tid"); + v = k5_json_array_get(a, 1); + check(k5_json_get_tid(v) == K5_JSON_TID_NULL, "fmt array[1] tid"); + v = k5_json_array_get(a, 2); + check(k5_json_get_tid(v) == K5_JSON_TID_BOOL, "fmt array[2] tid"); + check(k5_json_bool_value(v), "fmt array[2] value"); + v = k5_json_array_get(a, 3); + check(k5_json_get_tid(v) == K5_JSON_TID_NUMBER, "fmt array[3] tid"); + check(k5_json_number_value(v) == 9, "fmt array[3] value"); + v = k5_json_array_get(a, 4); + check(k5_json_get_tid(v) == K5_JSON_TID_NUMBER, "fmt array[4] tid"); + check(k5_json_number_value(v) == -6, "fmt array[4] value"); + v = k5_json_array_get(a, 5); + check(k5_json_get_tid(v) == K5_JSON_TID_STRING, "fmt array[5] tid"); + check(strcmp(k5_json_string_utf8(v), "def") == 0, "fmt array[5] value"); + v = k5_json_array_get(a, 6); + check(k5_json_get_tid(v) == K5_JSON_TID_NULL, "fmt array[6] tid"); + v = k5_json_array_get(a, 7); + check(k5_json_get_tid(v) == K5_JSON_TID_STRING, "fmt array[7] tid"); + check(strcmp(k5_json_string_utf8(v), "Z2hpag==") == 0, + "fmt array[7] value"); k5_json_release(v3); k5_json_release(a); } |