static void dict2json(heim_object_t key, heim_object_t value, void *ctx) { struct twojson *j = ctx; indent(j); base2json(key, j); j->out(j->ctx, " = "); base2json(value, j); j->out(j->ctx, ",\n"); }
static void array2json(heim_object_t value, void *ctx) { struct twojson *j = ctx; indent(j); base2json(value, j); j->out(j->ctx, ",\n"); j->indent--; }
static int heim_base2json(heim_object_t obj, void *ctx, void (*out)(void *, const char *)) { struct twojson j; j.indent = 0; j.ctx = ctx; j.out = out; return base2json(obj, &j); }
static void dict2json(heim_object_t key, heim_object_t value, void *ctx) { struct twojson *j = ctx; if (j->ret) return; if (j->first) { j->first = 0; } else { j->out(j->ctx, NULL); /* eat previous '\n' if possible */ j->out(j->ctx, ",\n"); } j->ret = base2json(key, j); if (j->ret) return; j->out(j->ctx, " : \n"); j->indent++; j->ret = base2json(value, j); if (j->ret) return; j->indent--; }
static void array2json(heim_object_t value, void *ctx, int *stop) { struct twojson *j = ctx; if (j->ret) return; if (j->first) { j->first = 0; } else { j->out(j->ctx, NULL); /* eat previous '\n' if possible */ j->out(j->ctx, ",\n"); } j->ret = base2json(value, j); }
static int heim_base2json(heim_object_t obj, void *ctx, heim_json_flags_t flags, void (*out)(void *, const char *)) { struct twojson j; if (flags & HEIM_JSON_F_STRICT_STRINGS) return ENOTSUP; /* Sorry, not yet! */ heim_base_once_f(&heim_json_once, NULL, json_init_once); j.indent = 0; j.ctx = ctx; j.out = out; j.flags = flags; j.ret = 0; j.first = 1; return base2json(obj, &j); }
static int base2json(heim_object_t obj, struct twojson *j) { heim_tid_t type; int first = 0; if (obj == NULL) { if (j->flags & HEIM_JSON_F_CNULL2JSNULL) { obj = heim_null_create(); } else if (j->flags & HEIM_JSON_F_NO_C_NULL) { return EINVAL; } else { indent(j); j->out(j->ctx, "<NULL>\n"); /* This is NOT valid JSON! */ return 0; } } type = heim_get_tid(obj); switch (type) { case HEIM_TID_ARRAY: indent(j); j->out(j->ctx, "[\n"); j->indent++; first = j->first; j->first = 1; heim_array_iterate_f(obj, j, array2json); j->indent--; if (!j->first) j->out(j->ctx, "\n"); indent(j); j->out(j->ctx, "]\n"); j->first = first; break; case HEIM_TID_DICT: indent(j); j->out(j->ctx, "{\n"); j->indent++; first = j->first; j->first = 1; heim_dict_iterate_f(obj, j, dict2json); j->indent--; if (!j->first) j->out(j->ctx, "\n"); indent(j); j->out(j->ctx, "}\n"); j->first = first; break; case HEIM_TID_STRING: indent(j); j->out(j->ctx, "\""); j->out(j->ctx, heim_string_get_utf8(obj)); j->out(j->ctx, "\""); break; case HEIM_TID_DATA: { heim_dict_t d; heim_string_t v; const heim_octet_string *data; char *b64 = NULL; int ret; if (j->flags & HEIM_JSON_F_NO_DATA) return EINVAL; /* JSON doesn't do binary */ data = heim_data_get_data(obj); ret = base64_encode(data->data, data->length, &b64); if (ret < 0 || b64 == NULL) return ENOMEM; if (j->flags & HEIM_JSON_F_NO_DATA_DICT) { indent(j); j->out(j->ctx, "\""); j->out(j->ctx, b64); /* base64-encode; hope there's no aliasing */ j->out(j->ctx, "\""); free(b64); } else { /* * JSON has no way to represent binary data, therefore the * following is a Heimdal-specific convention. * * We encode binary data as a dict with a single very magic * key with a base64-encoded value. The magic key includes * a uuid, so we're not likely to alias accidentally. */ d = heim_dict_create(2); if (d == NULL) { free(b64); return ENOMEM; } v = heim_string_ref_create(b64, free); if (v == NULL) { free(b64); heim_release(d); return ENOMEM; } ret = heim_dict_set_value(d, heim_tid_data_uuid_key, v); heim_release(v); if (ret) { heim_release(d); return ENOMEM; } ret = base2json(d, j); heim_release(d); if (ret) return ret; } break; } case HEIM_TID_NUMBER: { char num[32]; indent(j); snprintf(num, sizeof (num), "%d", heim_number_get_int(obj)); j->out(j->ctx, num); break; } case HEIM_TID_NULL: indent(j); j->out(j->ctx, "null"); break; case HEIM_TID_BOOL: indent(j); j->out(j->ctx, heim_bool_val(obj) ? "true" : "false"); break; default: return 1; } return 0; }