| /* 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 <ctype.h> |
| #include <stdlib.h> |
| |
| #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; |
| } |