/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "apr_json.h" #define APR_JSON_OBJECT_INSERT_TAIL(o, e) do { \ apr_json_kv_t *ap__b = (e); \ APR_RING_INSERT_TAIL(&(o)->list, ap__b, apr_json_kv_t, link); \ APR_RING_CHECK_CONSISTENCY(&(o)->list, apr_json_kv_t, link); \ } while (0) #define APR_JSON_ARRAY_INSERT_TAIL(o, e) do { \ apr_json_value_t *ap__b = (e); \ APR_RING_INSERT_TAIL(&(o)->list, ap__b, apr_json_value_t, link); \ APR_RING_CHECK_CONSISTENCY(&(o)->list, apr_json_value_t, link); \ } while (0) APR_DECLARE(apr_json_value_t *) apr_json_value_create(apr_pool_t *pool) { return apr_pcalloc(pool, sizeof(apr_json_value_t)); } APR_DECLARE(apr_json_value_t *) apr_json_object_create(apr_pool_t *pool) { apr_json_object_t *object; apr_json_value_t *json = apr_json_value_create(pool); json->type = APR_JSON_OBJECT; json->value.object = object = apr_pcalloc(pool, sizeof(apr_json_object_t)); APR_RING_INIT(&object->list, apr_json_kv_t, link); object->hash = apr_hash_make(pool); return json; } APR_DECLARE(apr_json_value_t *) apr_json_string_create(apr_pool_t *pool, const char *val, apr_ssize_t len) { apr_json_value_t *json = apr_json_value_create(pool); if (json) { if (val) { json->type = APR_JSON_STRING; json->value.string.p = val; json->value.string.len = len; } else { json->type = APR_JSON_NULL; } } return json; } APR_DECLARE(apr_json_value_t *) apr_json_array_create(apr_pool_t *pool, int nelts) { apr_json_value_t *json = apr_json_value_create(pool); if (json) { json->type = APR_JSON_ARRAY; json->value.array = apr_pcalloc(pool, sizeof(apr_json_array_t)); APR_RING_INIT(&json->value.array->list, apr_json_value_t, link); json->value.array->array = apr_array_make(pool, nelts, sizeof(apr_json_value_t *)); } return json; } APR_DECLARE(apr_json_value_t *) apr_json_long_create(apr_pool_t *pool, apr_int64_t lnumber) { apr_json_value_t *json = apr_json_value_create(pool); if (json) { json->type = APR_JSON_LONG; json->value.lnumber = lnumber; } return json; } APR_DECLARE(apr_json_value_t *) apr_json_double_create(apr_pool_t *pool, double dnumber) { apr_json_value_t *json = apr_json_value_create(pool); if (json) { json->type = APR_JSON_DOUBLE; json->value.dnumber = dnumber; } return json; } APR_DECLARE(apr_json_value_t *) apr_json_boolean_create(apr_pool_t *pool, int boolean) { apr_json_value_t *json = apr_json_value_create(pool); if (json) { json->type = APR_JSON_BOOLEAN; json->value.boolean = boolean; } return json; } APR_DECLARE(apr_json_value_t *) apr_json_null_create(apr_pool_t *pool) { apr_json_value_t *json = apr_json_value_create(pool); if (json) { json->type = APR_JSON_NULL; } return json; } APR_DECLARE(apr_status_t) apr_json_object_set(apr_json_value_t *object, const char *key, apr_ssize_t klen, apr_json_value_t *val, apr_pool_t *pool) { apr_json_kv_t *kv; apr_hash_t *hash; if (object->type != APR_JSON_OBJECT) { return APR_EINVAL; } if (klen == APR_JSON_VALUE_STRING) { klen = strlen(key); } hash = object->value.object->hash; kv = apr_hash_get(hash, key, klen); if (!val) { if (kv) { apr_hash_set(hash, key, klen, NULL); APR_RING_REMOVE((kv), link); } return APR_SUCCESS; } if (!kv) { kv = apr_palloc(pool, sizeof(apr_json_kv_t)); APR_RING_ELEM_INIT(kv, link); APR_JSON_OBJECT_INSERT_TAIL(object->value.object, kv); apr_hash_set(hash, key, klen, kv); } kv->k = apr_json_string_create(pool, key, klen); kv->v = val; return APR_SUCCESS; } APR_DECLARE(apr_status_t) apr_json_object_set_ex(apr_json_value_t *object, apr_json_value_t *key, apr_json_value_t *val, apr_pool_t *pool) { apr_json_kv_t *kv; apr_hash_t *hash; if (object->type != APR_JSON_OBJECT || key->type != APR_JSON_STRING) { return APR_EINVAL; } hash = object->value.object->hash; kv = apr_hash_get(hash, key->value.string.p, key->value.string.len); if (!val) { if (kv) { apr_hash_set(hash, key->value.string.p, key->value.string.len, NULL); APR_RING_REMOVE((kv), link); } return APR_SUCCESS; } if (!kv) { kv = apr_palloc(pool, sizeof(apr_json_kv_t)); APR_RING_ELEM_INIT(kv, link); APR_JSON_OBJECT_INSERT_TAIL(object->value.object, kv); apr_hash_set(hash, key->value.string.p, key->value.string.len, kv); } kv->k = key; kv->v = val; return APR_SUCCESS; } APR_DECLARE(apr_json_kv_t *) apr_json_object_get(apr_json_value_t *object, const char *key, apr_ssize_t klen) { if (object->type != APR_JSON_OBJECT) { return NULL; } return apr_hash_get(object->value.object->hash, key, klen); } APR_DECLARE(apr_json_kv_t *) apr_json_object_first(apr_json_value_t *obj) { apr_json_kv_t *kv; if (obj->type != APR_JSON_OBJECT) { return NULL; } kv = APR_RING_FIRST(&(obj->value.object)->list); if (kv != APR_RING_SENTINEL(&(obj->value.object)->list, apr_json_kv_t, link)) { return kv; } else { return NULL; } } APR_DECLARE(apr_json_kv_t *) apr_json_object_next(apr_json_value_t *obj, apr_json_kv_t *kv) { apr_json_kv_t *next; if (obj->type != APR_JSON_OBJECT) { return NULL; } next = APR_RING_NEXT((kv), link); if (next != APR_RING_SENTINEL(&(obj->value.object)->list, apr_json_kv_t, link)) { return next; } else { return NULL; } } APR_DECLARE(apr_status_t) apr_json_array_add(apr_json_value_t *arr, apr_json_value_t *val) { apr_array_header_t *array; if (arr->type != APR_JSON_ARRAY) { return APR_EINVAL; } APR_RING_ELEM_INIT(val, link); APR_JSON_ARRAY_INSERT_TAIL(arr->value.array, val); array = arr->value.array->array; if (array) { *((apr_json_value_t **) (apr_array_push(array))) = val; } return APR_SUCCESS; } APR_DECLARE(apr_json_value_t *) apr_json_array_get(apr_json_value_t *arr, int index) { if (arr->type != APR_JSON_ARRAY) { return NULL; } return APR_ARRAY_IDX(arr->value.array->array, index, apr_json_value_t *); } APR_DECLARE(apr_json_value_t *) apr_json_array_first(const apr_json_value_t *arr) { apr_json_value_t *val; if (arr->type != APR_JSON_ARRAY) { return NULL; } val = APR_RING_FIRST(&(arr->value.array)->list); if (val != APR_RING_SENTINEL(&(arr->value.object)->list, apr_json_value_t, link)) { return val; } else { return NULL; } } APR_DECLARE(apr_json_value_t *) apr_json_array_next(const apr_json_value_t *arr, const apr_json_value_t *val) { apr_json_value_t *next; if (arr->type != APR_JSON_ARRAY) { return NULL; } next = APR_RING_NEXT((val), link); if (next != APR_RING_SENTINEL(&(arr->value.array)->list, apr_json_value_t, link)) { return next; } else { return NULL; } } APR_DECLARE(apr_json_value_t *) apr_json_overlay(apr_pool_t *p, apr_json_value_t *overlay, apr_json_value_t *base, int flags) { apr_json_value_t *res; apr_json_kv_t *kv; int oc, bc; if (!base || base->type != APR_JSON_OBJECT) { return overlay; } if (!overlay) { return base; } if (overlay->type != APR_JSON_OBJECT) { return overlay; } oc = apr_hash_count(overlay->value.object->hash); if (!oc) { return base; } bc = apr_hash_count(base->value.object->hash); if (!bc) { return overlay; } res = apr_json_object_create(p); for (kv = APR_RING_FIRST(&(base->value.object)->list); kv != APR_RING_SENTINEL(&(base->value.object)->list, apr_json_kv_t, link); kv = APR_RING_NEXT((kv), link)) { if (!apr_hash_get(overlay->value.object->hash, kv->k->value.string.p, kv->k->value.string.len)) { apr_json_object_set_ex(res, kv->k, kv->v, p); } else if (APR_JSON_FLAGS_STRICT & flags) { return NULL; } } for (kv = APR_RING_FIRST(&(overlay->value.object)->list); kv != APR_RING_SENTINEL(&(overlay->value.object)->list, apr_json_kv_t, link); kv = APR_RING_NEXT((kv), link)) { apr_json_object_set_ex(res, kv->k, kv->v, p); } return res; }