blob: 942d520330383ab16afc7fc7ca12e5d548e3dc80 [file] [log] [blame]
/**
*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 "json_serializer.h"
#include "dyn_type.h"
#include "dyn_interface.h"
#include <jansson.h>
#include <assert.h>
#include <stdint.h>
#include <string.h>
static int jsonSerializer_createType(dyn_type *type, json_t *object, void **result);
static int jsonSerializer_parseObject(dyn_type *type, json_t *object, void *inst);
static int jsonSerializer_parseObjectMember(dyn_type *type, const char *name, json_t *val, void *inst);
static int jsonSerializer_parseSequence(dyn_type *seq, json_t *array, void *seqLoc);
static int jsonSerializer_parseAny(dyn_type *type, void *input, json_t *val);
static int jsonSerializer_writeAny(dyn_type *type, void *input, json_t **val);
static int jsonSerializer_writeComplex(dyn_type *type, void *input, json_t **val);
static int jsonSerializer_writeSequence(dyn_type *type, void *input, json_t **out);
static int OK = 0;
static int ERROR = 1;
DFI_SETUP_LOG(jsonSerializer);
int jsonSerializer_deserialize(dyn_type *type, const char *input, void **result) {
assert(dynType_type(type) == DYN_TYPE_COMPLEX || dynType_type(type) == DYN_TYPE_SEQUENCE);
int status = 0;
json_error_t error;
json_t *root = json_loads(input, JSON_DECODE_ANY, &error);
if (root != NULL) {
status = jsonSerializer_deserializeJson(type, root, result);
json_decref(root);
} else {
status = ERROR;
LOG_ERROR("Error parsing json input '%s'. Error is: %s\n", input, error.text);
}
return status;
}
int jsonSerializer_deserializeJson(dyn_type *type, json_t *input, void **out) {
return jsonSerializer_createType(type, input, out);
}
static int jsonSerializer_createType(dyn_type *type, json_t *val, void **result) {
assert(val != NULL);
int status = OK;
void *inst = NULL;
status = dynType_alloc(type, &inst);
if (status == OK) {
assert(inst != NULL);
status = jsonSerializer_parseAny(type, inst, val);
if (status != OK) {
dynType_free(type, inst);
}
}
if (status == OK) {
*result = inst;
}
return status;
}
static int jsonSerializer_parseObject(dyn_type *type, json_t *object, void *inst) {
assert(object != NULL);
int status = 0;
json_t *value;
const char *key;
json_object_foreach(object, key, value) {
status = jsonSerializer_parseObjectMember(type, key, value, inst);
if (status != OK) {
break;
}
}
return status;
}
static int jsonSerializer_parseObjectMember(dyn_type *type, const char *name, json_t *val, void *inst) {
int status = OK;
void *valp = NULL;
dyn_type *valType = NULL;
int index = dynType_complex_indexForName(type, name);
if (index < 0) {
LOG_ERROR("Cannot find index for member '%s'", name);
status = ERROR;
}
if (status == OK) {
status = dynType_complex_valLocAt(type, index, inst, &valp);
}
if (status == OK ) {
status = dynType_complex_dynTypeAt(type, index, &valType);
}
if (status == OK) {
status = jsonSerializer_parseAny(valType, valp, val);
}
return status;
}
static int jsonSerializer_parseAny(dyn_type *type, void *loc, json_t *val) {
int status = OK;
dyn_type *subType = NULL;
char c = dynType_descriptorType(type);
/*
printf("parseAny with descriptor '%c' :", c);
json_dumpf(val, stdout, 0); //TODO remove
printf("\n");
*/
bool *z; //Z
float *f; //F
double *d; //D
char *b; //B
int *n; //N
int16_t *s; //S
int32_t *i; //I
int64_t *l; //J
uint8_t *ub; //b
uint16_t *us; //s
uint32_t *ui; //i
uint64_t *ul; //j
switch (c) {
case 'Z' :
z = loc;
*z = (bool) json_is_true(val);
break;
case 'F' :
f = loc;
*f = (float) json_real_value(val);
break;
case 'D' :
d = loc;
*d = json_real_value(val);
break;
case 'N' :
n = loc;
*n = (int) json_real_value(val);
break;
case 'B' :
b = loc;
*b = (char) json_integer_value(val);
break;
case 'S' :
s = loc;
*s = (int16_t) json_integer_value(val);
break;
case 'I' :
i = loc;
*i = (int32_t) json_integer_value(val);
break;
case 'J' :
l = loc;
*l = (int64_t) json_integer_value(val);
break;
case 'b' :
ub = loc;
*ub = (uint8_t) json_integer_value(val);
break;
case 's' :
us = loc;
*us = (uint16_t) json_integer_value(val);
break;
case 'i' :
ui = loc;
*ui = (uint32_t) json_integer_value(val);
break;
case 'j' :
ul = loc;
*ul = (uint64_t) json_integer_value(val);
break;
case 't' :
if (json_is_string(val)) {
dynType_text_allocAndInit(type, loc, json_string_value(val));
} else {
status = ERROR;
LOG_ERROR("Expected json string type got %i", json_typeof(val));
}
break;
case '[' :
if (json_is_array(val)) {
status = jsonSerializer_parseSequence(type, val, loc);
} else {
status = ERROR;
LOG_ERROR("Expected json array type got '%i'", json_typeof(val));
}
break;
case '{' :
if (status == OK) {
status = jsonSerializer_parseObject(type, val, loc);
}
break;
case '*' :
status = dynType_typedPointer_getTypedType(type, &subType);
if (status == OK) {
status = jsonSerializer_createType(subType, val, (void **) loc);
}
break;
case 'P' :
status = ERROR;
LOG_WARNING("Untyped pointer are not supported for serialization");
break;
default :
status = ERROR;
LOG_ERROR("Error provided type '%c' not supported for JSON\n", dynType_descriptorType(type));
break;
}
return status;
}
static int jsonSerializer_parseSequence(dyn_type *seq, json_t *array, void *seqLoc) {
assert(dynType_type(seq) == DYN_TYPE_SEQUENCE);
int status = OK;
size_t size = json_array_size(array);
//LOG_DEBUG("Allocating sequence with capacity %zu", size);
status = dynType_sequence_alloc(seq, seqLoc, (int) size);
if (status == OK) {
dyn_type *itemType = dynType_sequence_itemType(seq);
size_t index;
json_t *val;
json_array_foreach(array, index, val) {
void *valLoc = NULL;
status = dynType_sequence_increaseLengthAndReturnLastLoc(seq, seqLoc, &valLoc);
//LOG_DEBUG("Got sequence loc %p for index %zu", valLoc, index);
if (status == OK) {
status = jsonSerializer_parseAny(itemType, valLoc, val);
if (status != OK) {
break;
}
}
}
}
return status;
}
int jsonSerializer_serialize(dyn_type *type, void *input, char **output) {
int status = OK;
json_t *root = NULL;
status = jsonSerializer_serializeJson(type, input, &root);
if (status == OK) {
*output = json_dumps(root, JSON_COMPACT);
json_decref(root);
}
return status;
}
int jsonSerializer_serializeJson(dyn_type *type, void *input, json_t **out) {
return jsonSerializer_writeAny(type, input, out);
}
static int jsonSerializer_writeAny(dyn_type *type, void *input, json_t **out) {
int status = OK;
int descriptor = dynType_descriptorType(type);
json_t *val = NULL;
dyn_type *subType = NULL;
bool *z; //Z
float *f; //F
double *d; //D
char *b; //B
int *n; //N
int16_t *s; //S
int32_t *i; //I
int64_t *l; //J
uint8_t *ub; //b
uint16_t *us; //s
uint32_t *ui; //i
uint64_t *ul; //j
switch (descriptor) {
case 'Z' :
z = input;
val = json_boolean((bool)*z);
break;
case 'B' :
b = input;
val = json_integer((json_int_t)*b);
break;
case 'S' :
s = input;
val = json_integer((json_int_t)*s);
break;
case 'I' :
i = input;
val = json_integer((json_int_t)*i);
break;
case 'J' :
l = input;
val = json_integer((json_int_t)*l);
break;
case 'b' :
ub = input;
val = json_integer((json_int_t)*ub);
break;
case 's' :
us = input;
val = json_integer((json_int_t)*us);
break;
case 'i' :
ui = input;
val = json_integer((json_int_t)*ui);
break;
case 'j' :
ul = input;
val = json_integer((json_int_t)*ul);
break;
case 'N' :
n = input;
val = json_integer((json_int_t)*n);
break;
case 'F' :
f = input;
val = json_real((double) *f);
break;
case 'D' :
d = input;
val = json_real(*d);
break;
case 't' :
val = json_string(*(const char **) input);
break;
case '*' :
status = dynType_typedPointer_getTypedType(type, &subType);
if (status == OK) {
status = jsonSerializer_writeAny(subType, *(void **)input, &val);
}
break;
case '{' :
status = jsonSerializer_writeComplex(type, input, &val);
break;
case '[' :
status = jsonSerializer_writeSequence(type, input, &val);
break;
case 'P' :
LOG_WARNING("Untyped pointer not supported for serialization. ignoring");
break;
default :
LOG_ERROR("Unsupported descriptor '%c'", descriptor);
status = ERROR;
break;
}
if (status == OK && val != NULL) {
*out = val;
}
return status;
}
static int jsonSerializer_writeSequence(dyn_type *type, void *input, json_t **out) {
assert(dynType_type(type) == DYN_TYPE_SEQUENCE);
int status = OK;
json_t *array = json_array();
dyn_type *itemType = dynType_sequence_itemType(type);
uint32_t len = dynType_sequence_length(input);
int i = 0;
void *itemLoc = NULL;
json_t *item = NULL;
for (i = 0; i < len; i += 1) {
item = NULL;
status = dynType_sequence_locForIndex(type, input, i, &itemLoc);
if (status == OK) {
status = jsonSerializer_writeAny(itemType, itemLoc, &item);
if (status == OK) {
json_array_append(array, item);
json_decref(item);
}
}
if (status != OK) {
break;
}
}
if (status == OK && array != NULL) {
*out = array;
}
return status;
}
static int jsonSerializer_writeComplex(dyn_type *type, void *input, json_t **out) {
assert(dynType_type(type) == DYN_TYPE_COMPLEX);
int status = OK;
json_t *val = json_object();
struct complex_type_entry *entry = NULL;
struct complex_type_entries_head *entries = NULL;
int index = -1;
status = dynType_complex_entries(type, &entries);
if (status == OK) {
TAILQ_FOREACH(entry, entries, entries) {
void *subLoc = NULL;
json_t *subVal = NULL;
dyn_type *subType = NULL;
index = dynType_complex_indexForName(type, entry->name);
status = dynType_complex_valLocAt(type, index, input, &subLoc);
if (status == OK ) {
status = dynType_complex_dynTypeAt(type, index, &subType);
}
if (status == OK) {
status = jsonSerializer_writeAny(subType, subLoc, &subVal);
}
if (status == OK) {
json_object_set(val, entry->name, subVal);
json_decref(subVal);
}
if (status != OK) {
break;
}
}
}
if (status == OK && val != NULL) {
*out = val;
}
return status;
}