CELIX-237: Updated serialized. Added parse tests and conresponding implementation and added write functionality
Project: http://git-wip-us.apache.org/repos/asf/celix/repo Commit: http://git-wip-us.apache.org/repos/asf/celix/commit/24d13f2e Tree: http://git-wip-us.apache.org/repos/asf/celix/tree/24d13f2e Diff: http://git-wip-us.apache.org/repos/asf/celix/diff/24d13f2e Branch: refs/heads/feature/CELIX-237_rsa-ffi Commit: 24d13f2ef08de444739e441471e87b349eb6972e Parents: 9f2ea10 Author: Pepijn Noltes <pepijnnol...@gmail.com> Authored: Fri Jul 31 12:17:30 2015 +0200 Committer: Pepijn Noltes <pepijnnol...@gmail.com> Committed: Fri Jul 31 12:17:30 2015 +0200 ---------------------------------------------------------------------- .../dynamic_function_interface/dyn_type.c | 234 ++++++++--- .../dynamic_function_interface/dyn_type.h | 30 +- .../json_serializer.c | 407 +++++++++++++++---- .../json_serializer.h | 8 +- .../tst/json_serializer_tests.cpp | 265 ++++++++++-- 5 files changed, 765 insertions(+), 179 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/celix/blob/24d13f2e/remote_services/dynamic_function_interface/dyn_type.c ---------------------------------------------------------------------- diff --git a/remote_services/dynamic_function_interface/dyn_type.c b/remote_services/dynamic_function_interface/dyn_type.c index f90f432..6de9736 100644 --- a/remote_services/dynamic_function_interface/dyn_type.c +++ b/remote_services/dynamic_function_interface/dyn_type.c @@ -47,43 +47,45 @@ static void dynType_printTypes(dyn_type *type, FILE *stream); static void dynType_printComplexType(dyn_type *type, FILE *stream); static void dynType_printSimpleType(dyn_type *type, FILE *stream); +static int dynType_parseText(FILE *stream, dyn_type *type); + struct generic_sequence { uint32_t cap; uint32_t len; void *buf; }; -static const int DT_OK = 0; -static const int DT_ERROR = 1; -static const int DT_MEM_ERROR = 2; -static const int DT_PARSE_ERROR = 3; +static const int OK = 0; +static const int ERROR = 1; +static const int MEM_ERROR = 2; +static const int PARSE_ERROR = 3; int dynType_parse(FILE *descriptorStream, const char *name, struct reference_types_head *refTypes, dyn_type **type) { return dynType_parseWithStream(descriptorStream, name, NULL, refTypes, type); } int dynType_parseWithStr(const char *descriptor, const char *name, struct reference_types_head *refTypes, dyn_type **type) { - int status = DT_OK; + int status = OK; FILE *stream = fmemopen((char *)descriptor, strlen(descriptor), "r"); if (stream != NULL) { status = dynType_parseWithStream(stream, name, NULL, refTypes, type); - if (status == DT_OK) { + if (status == OK) { int c = fgetc(stream); if (c != '\0' && c != EOF) { - status = DT_PARSE_ERROR; + status = PARSE_ERROR; LOG_ERROR("Expected EOF got %c", c); } } fclose(stream); } else { - status = DT_ERROR; + status = ERROR; LOG_ERROR("Error creating mem stream for descriptor string. %s", strerror(errno)); } return status; } static int dynType_parseWithStream(FILE *stream, const char *name, dyn_type *parent, struct reference_types_head *refTypes, dyn_type **result) { - int status = DT_OK; + int status = OK; dyn_type *type = calloc(1, sizeof(*type)); if (type != NULL) { type->parent = parent; @@ -93,33 +95,33 @@ static int dynType_parseWithStream(FILE *stream, const char *name, dyn_type *par if (name != NULL) { type->name = strdup(name); if (type->name == NULL) { - status = DT_MEM_ERROR; + status = MEM_ERROR; LOG_ERROR("Error strdup'ing name '%s'\n", name); } } - if (status == DT_OK) { + if (status == OK) { status = dynType_parseAny(stream, type); } - if (status == DT_OK) { + if (status == OK) { *result = type; } else { dynType_destroy(type); } } else { - status = DT_MEM_ERROR; + status = MEM_ERROR; LOG_ERROR("Error allocating memory for type"); } return status; } static int dynType_parseAny(FILE *stream, dyn_type *type) { - int status = DT_OK; + int status = OK; int c = fgetc(stream); switch(c) { case 'T' : status = dynType_parseNestedType(stream, type); - if (status == DT_OK) { + if (status == OK) { status = dynType_parseAny(stream, type); } break; @@ -138,6 +140,9 @@ static int dynType_parseAny(FILE *stream, dyn_type *type) { case '*' : status = dynType_parseTypedPointer(stream, type); break; + case 't' : + status = dynType_parseText(stream, type); + break; default : status = dynType_parseSimple(c, type); break; @@ -146,8 +151,16 @@ static int dynType_parseAny(FILE *stream, dyn_type *type) { return status; } +static int dynType_parseText(FILE *stream, dyn_type *type) { + int status = OK; + type->type = DYN_TYPE_TEXT; + type->descriptor = 't'; + type->ffiType = &ffi_type_pointer; + return status; +} + static int dynType_parseComplex(FILE *stream, dyn_type *type) { - int status = DT_OK; + int status = OK; type->type = DYN_TYPE_COMPLEX; type->descriptor = '{'; type->ffiType = &type->complex.structType; @@ -165,7 +178,7 @@ static int dynType_parseComplex(FILE *stream, dyn_type *type) { TAILQ_INSERT_TAIL(&type->complex.entriesHead, entry, entries); status = dynType_parseAny(stream, &entry->type); } else { - status = DT_MEM_ERROR; + status = MEM_ERROR; LOG_ERROR("Error allocating memory for type"); } c = fgetc(stream); @@ -175,7 +188,7 @@ static int dynType_parseComplex(FILE *stream, dyn_type *type) { char *name = NULL; while (c == ' ' && entry != NULL) { status = dynCommon_parseName(stream, &name); - if (status == DT_OK) { + if (status == OK) { entry->name = name; entry = TAILQ_NEXT(entry, entries); } else { @@ -189,7 +202,7 @@ static int dynType_parseComplex(FILE *stream, dyn_type *type) { count +=1; } - if (status == DT_OK) { + if (status == OK) { type->complex.structType.type = FFI_TYPE_STRUCT; type->complex.structType.elements = calloc(count + 1, sizeof(ffi_type)); type->complex.structType.elements[count] = NULL; @@ -199,12 +212,12 @@ static int dynType_parseComplex(FILE *stream, dyn_type *type) { type->complex.structType.elements[index++] = entry->type.ffiType; } } else { - status = DT_MEM_ERROR; + status = MEM_ERROR; //T\nODO log: error allocating memory } } - if (status == DT_OK) { + if (status == OK) { type->complex.types = calloc(count, sizeof(dyn_type *)); if (type != NULL) { int index = 0; @@ -212,12 +225,12 @@ static int dynType_parseComplex(FILE *stream, dyn_type *type) { type->complex.types[index++] = &entry->type; } } else { - status = DT_MEM_ERROR; + status = MEM_ERROR; LOG_ERROR("Error allocating memory for type") } } - if (status == DT_OK) { + if (status == OK) { dynType_prepCif(type->ffiType); } @@ -226,7 +239,7 @@ static int dynType_parseComplex(FILE *stream, dyn_type *type) { } static int dynType_parseNestedType(FILE *stream, dyn_type *type) { - int status = DT_OK; + int status = OK; char *name = NULL; struct nested_entry *entry = NULL; @@ -239,22 +252,22 @@ static int dynType_parseNestedType(FILE *stream, dyn_type *type) { status = dynCommon_parseName(stream, &name); entry->type.name = name; } else { - status = DT_MEM_ERROR; + status = MEM_ERROR; } - if (status == DT_OK) { + if (status == OK) { int c = fgetc(stream); if (c != '=') { - status = DT_PARSE_ERROR; + status = PARSE_ERROR; LOG_ERROR("Error parsing nested type expected '=' got '%c'", c); } } - if (status == DT_OK) { + if (status == OK) { status = dynType_parseAny(stream, &entry->type); int c = fgetc(stream); if (c != ';') { - status = DT_PARSE_ERROR; + status = PARSE_ERROR; LOG_ERROR("Expected ';' got '%c'\n", c); } } @@ -263,7 +276,7 @@ static int dynType_parseNestedType(FILE *stream, dyn_type *type) { } static int dynType_parseReference(FILE *stream, dyn_type *type) { - int status = DT_OK; + int status = OK; type->type = DYN_TYPE_TYPED_POINTER; type->descriptor = '*'; @@ -279,7 +292,7 @@ static int dynType_parseReference(FILE *stream, dyn_type *type) { TAILQ_INIT(&subType->nestedTypesHead); status = dynType_parseRefByValue(stream, subType); } else { - status = DT_MEM_ERROR; + status = MEM_ERROR; LOG_ERROR("Error allocating memory for subtype\n"); } @@ -287,27 +300,27 @@ static int dynType_parseReference(FILE *stream, dyn_type *type) { } static int dynType_parseRefByValue(FILE *stream, dyn_type *type) { - int status = DT_OK; + int status = OK; type->type = DYN_TYPE_REF; type->descriptor = 'l'; char *name = NULL; status = dynCommon_parseName(stream, &name); - if (status == DT_OK) { + if (status == OK) { dyn_type *ref = dynType_findType(type, name); if (ref != NULL) { type->ref.ref = ref; } else { - status = DT_PARSE_ERROR; + status = PARSE_ERROR; LOG_ERROR("Error cannot find type '%s'", name); } free(name); } - if (status == DT_OK) { + if (status == OK) { int c = fgetc(stream); if (c != ';') { - status = DT_PARSE_ERROR; + status = PARSE_ERROR; LOG_ERROR("Error expected ';' got '%c'", c); } } @@ -318,14 +331,14 @@ static int dynType_parseRefByValue(FILE *stream, dyn_type *type) { static ffi_type *seq_types[] = {&ffi_type_uint32, &ffi_type_uint32, &ffi_type_pointer, NULL}; static int dynType_parseSequence(FILE *stream, dyn_type *type) { - int status = DT_OK; + int status = OK; type->type = DYN_TYPE_SEQUENCE; type->descriptor = '['; type->sequence.seqType.elements = seq_types; status = dynType_parseWithStream(stream, NULL, type, NULL, &type->sequence.itemType); - if (status == DT_OK) { + if (status == OK) { type->ffiType = &type->sequence.seqType; dynType_prepCif(&type->sequence.seqType); } @@ -334,14 +347,14 @@ static int dynType_parseSequence(FILE *stream, dyn_type *type) { } static int dynType_parseSimple(int c, dyn_type *type) { - int status = DT_OK; + int status = OK; ffi_type *ffiType = dynType_ffiTypeFor(c); if (ffiType != NULL) { type->type = DYN_TYPE_SIMPLE; type->descriptor = c; type->ffiType = ffiType; } else { - status = DT_PARSE_ERROR; + status = PARSE_ERROR; LOG_ERROR("Error unsupported type '%c'", c); } @@ -349,7 +362,7 @@ static int dynType_parseSimple(int c, dyn_type *type) { } static int dynType_parseTypedPointer(FILE *stream, dyn_type *type) { - int status = DT_OK; + int status = OK; type->type = DYN_TYPE_TYPED_POINTER; type->descriptor = '*'; type->ffiType = &ffi_type_pointer; @@ -436,14 +449,17 @@ static void dynType_clearTypedPointer(dyn_type *type) { } int dynType_alloc(dyn_type *type, void **bufLoc) { - int status = DT_OK; + assert(type->type != DYN_TYPE_REF); + int status = OK; + void *inst = calloc(1, type->ffiType->size); if (inst != NULL) { *bufLoc = inst; } else { - status = DT_MEM_ERROR; + status = MEM_ERROR; LOG_ERROR("Error allocating memory for type '%c'", type->descriptor); } + return status; } @@ -471,7 +487,11 @@ char dynType_complex_descriptorTypeAt(dyn_type *type, int index) { int dynType_complex_dynTypeAt(dyn_type *type, int index, dyn_type **result) { assert(type->type == DYN_TYPE_COMPLEX); - *result = type->complex.types[index]; + dyn_type *sub = type->complex.types[index]; + if (sub->type == DYN_TYPE_REF) { + sub = sub->ref.ref; + } + *result = sub; return 0; } @@ -491,10 +511,17 @@ int dynType_complex_valLocAt(dyn_type *type, int index, void *inst, void **resul return 0; } +int dynType_complex_entries(dyn_type *type, struct complex_type_entries_head **entries) { + assert(type->type == DYN_TYPE_COMPLEX); + int status = OK; + *entries = &type->complex.entriesHead; + return status; +} + //sequence int dynType_sequence_alloc(dyn_type *type, void *inst, int cap, void **out) { assert(type->type == DYN_TYPE_SEQUENCE); - int status = DT_OK; + int status = OK; struct generic_sequence *seq = inst; if (seq != NULL) { size_t size = dynType_size(type->sequence.itemType); @@ -505,11 +532,11 @@ int dynType_sequence_alloc(dyn_type *type, void *inst, int cap, void **out) { *out = seq->buf; } else { seq->cap = 0; - status = DT_MEM_ERROR; + status = MEM_ERROR; LOG_ERROR("Error allocating memory for buf") } } else { - status = DT_MEM_ERROR; + status = MEM_ERROR; LOG_ERROR("Error allocating memory for seq") } return status; @@ -517,31 +544,73 @@ int dynType_sequence_alloc(dyn_type *type, void *inst, int cap, void **out) { void dynType_free(dyn_type *type, void *loc) { //TODO - LOG_INFO("TODO"); + LOG_INFO("TODO dynType_free"); } -int dynType_sequence_append(dyn_type *type, void *inst, void *in) { +uint32_t dynType_sequence_length(void *seqLoc) { + struct generic_sequence *seq = seqLoc; + return seq->len; +} + +int dynType_sequence_locForIndex(dyn_type *type, void *seqLoc, int index, void **out) { assert(type->type == DYN_TYPE_SEQUENCE); - int status = DT_OK; - int index = -1; - struct generic_sequence *seq = inst; - if (seq->len + 1 <= seq->cap) { - index = seq->len; + int status = OK; + + struct generic_sequence *seq = seqLoc; + char *valLoc = seq->buf; + size_t itemSize = type->sequence.itemType->ffiType->size; + + if (index >= seq->cap) { + status = ERROR; + LOG_ERROR("Requested index (%i) is greater than capacity (%u) of sequence", index, seq->cap); + } + + if (index >= seq->len) { + LOG_WARNING("Requesting index (%i) outsize defined length (%u) but within capacity", index, seq->len); + } + + if (status == OK) { } + int i; + for (i = 0; i < seq->cap; i += 1) { + if (index == i) { + break; + } else { + valLoc += itemSize; + } + } + + (*out) = valLoc; + + return status; +} + +int dynType_sequence_increaseLengthAndReturnLastLoc(dyn_type *type, void *seqLoc, void **valLoc) { + assert(type->type == DYN_TYPE_SEQUENCE); + int status = OK; + struct generic_sequence *seq = seqLoc; + + int lastIndex = seq->len; + if (seq->len < seq->cap) { seq->len += 1; - char *buf = seq->buf; - size_t elSize = dynType_size(type->sequence.itemType); - size_t offset = (elSize * index); - memcpy(buf + offset, in, elSize); } else { - status = DT_ERROR; - LOG_ERROR("Sequence out of capacity") + status = ERROR; + LOG_ERROR("Cannot increase sequence length beyond capacity (%u)", seq->cap); + } + + if (status == OK) { + status = dynType_sequence_locForIndex(type, seqLoc, lastIndex, valLoc); } + return status; } dyn_type * dynType_sequence_itemType(dyn_type *type) { assert(type->type == DYN_TYPE_SEQUENCE); - return type->sequence.itemType; + dyn_type *itemType = type->sequence.itemType; + if (itemType->type == DYN_TYPE_REF) { + itemType = itemType->ref.ref; + } + return itemType; } void dynType_simple_setValue(dyn_type *type, void *inst, void *in) { @@ -658,6 +727,48 @@ int dynType_type(dyn_type *type) { return type->type; } + +int dynType_typedPointer_getTypedType(dyn_type *type, dyn_type **out) { + assert(type->type == DYN_TYPE_TYPED_POINTER); + int status = 0; + + dyn_type *typedType = type->typedPointer.typedType; + if (typedType->type == DYN_TYPE_REF) { + typedType = typedType->ref.ref; + } + + *out = typedType; + return status; +} + + +int dynType_text_allocAndInit(dyn_type *type, void *textLoc, const char *value) { + int status = 0; + const char *str = strdup(value); + char const **loc = textLoc; + if (str != NULL) { + *loc = str; + } else { + status = ERROR; + LOG_ERROR("Cannot allocate memory for string"); + } + return status; +} + + + + + + + + + + + + + + + void dynType_print(dyn_type *type, FILE *stream) { if (type != NULL) { dynType_printTypes(type, stream); @@ -814,3 +925,4 @@ static void dynType_printComplexType(dyn_type *type, FILE *stream) { static void dynType_printSimpleType(dyn_type *type, FILE *stream) { fprintf(stream, "\ttype '%s': simple type, size is %zu, alignment is %i, descriptor is '%c'\n", type->name, type->ffiType->size, type->ffiType->alignment, type->descriptor); } + http://git-wip-us.apache.org/repos/asf/celix/blob/24d13f2e/remote_services/dynamic_function_interface/dyn_type.h ---------------------------------------------------------------------- diff --git a/remote_services/dynamic_function_interface/dyn_type.h b/remote_services/dynamic_function_interface/dyn_type.h index a09a9da..bf6dfc8 100644 --- a/remote_services/dynamic_function_interface/dyn_type.h +++ b/remote_services/dynamic_function_interface/dyn_type.h @@ -10,6 +10,7 @@ #include <stdbool.h> #include <ffi.h> +#include <stdint.h> #include "dfi_log_util.h" @@ -40,26 +41,28 @@ * i uint32_t * j uint62_t * s uint64_t - * P pointer + * P untyped pointer (void *) * t char* string * N native int * - * * ComplexTypes (Struct) * {[Type]+ [(Name)(SPACE)]+} * - * PointerReference - * L(Name); - * * ReferenceByValue * l(name); * + * PointerReference -> note shortcut for *l(name); + * L(Name); + * * TypeDef * T(Name)=Type; * * SequenceType * [(Type) * + * TypedPointer + * *(Type) + * * Annotation TODO * <(Name)=(Value)> * @@ -75,12 +78,14 @@ #define DYN_TYPE_COMPLEX 2 #define DYN_TYPE_SEQUENCE 3 #define DYN_TYPE_TYPED_POINTER 4 -#define DYN_TYPE_REF 5 +#define DYN_TYPE_TEXT 5 +#define DYN_TYPE_REF 6 typedef struct _dyn_type dyn_type; TAILQ_HEAD(reference_types_head, type_entry); -TAILQ_HEAD(nested_types_head, nested_entry); +TAILQ_HEAD(nested_types_head, nested_entry); +TAILQ_HEAD(complex_type_entries_head, complex_type_entry); struct _dyn_type { char *name; @@ -92,7 +97,7 @@ struct _dyn_type { struct nested_types_head nestedTypesHead; union { struct { - TAILQ_HEAD(, complex_type_entry) entriesHead; + struct complex_type_entries_head entriesHead; ffi_type structType; //dyn_type.ffiType points to this dyn_type **types; //based on entriesHead for fast access } complex; @@ -147,11 +152,18 @@ char dynType_complex_descriptorTypeAt(dyn_type *type, int index); int dynType_complex_dynTypeAt(dyn_type *type, int index, dyn_type **subType); int dynType_complex_setValueAt(dyn_type *type, int index, void *inst, void *in); int dynType_complex_valLocAt(dyn_type *type, int index, void *inst, void **valLoc); +int dynType_complex_entries(dyn_type *type, struct complex_type_entries_head **entries); //sequence int dynType_sequence_alloc(dyn_type *type, void *inst, int cap, void **buf); -int dynType_sequence_append(dyn_type *type, void *seq, void *in); +int dynType_sequence_locForIndex(dyn_type *type, void *seqLoc, int index, void **valLoc); +int dynType_sequence_increaseLengthAndReturnLastLoc(dyn_type *type, void *seqLoc, void **valLoc); dyn_type * dynType_sequence_itemType(dyn_type *type); +uint32_t dynType_sequence_length(void *seqLoc); + +int dynType_typedPointer_getTypedType(dyn_type *type, dyn_type **typedType); + +int dynType_text_allocAndInit(dyn_type *type, void *textLoc, const char *value); //simple void dynType_simple_setValue(dyn_type *type, void *inst, void *in); http://git-wip-us.apache.org/repos/asf/celix/blob/24d13f2e/remote_services/dynamic_function_interface/json_serializer.c ---------------------------------------------------------------------- diff --git a/remote_services/dynamic_function_interface/json_serializer.c b/remote_services/dynamic_function_interface/json_serializer.c index 628bec9..3fbdda4 100644 --- a/remote_services/dynamic_function_interface/json_serializer.c +++ b/remote_services/dynamic_function_interface/json_serializer.c @@ -1,17 +1,32 @@ -/** +/* * Licensed under Apache License v2. See LICENSE for more information. */ #include "json_serializer.h" +#include "dyn_type.h" #include <jansson.h> #include <assert.h> +#include <stdint.h> +#include <string.h> -static int json_serializer_createObject(dyn_type *type, json_t *object, void **result); -static int json_serializer_writeObject(dyn_type *type, json_t *object, void *inst); -static void json_serializer_writeObjectMember(dyn_type *type, const char *name, json_t *val, void *inst); -static void json_serializer_writeSequence(json_t *array, dyn_type *seq, void *seqLoc); +static int jsonSerializer_createObject(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); -int json_deserialize(dyn_type *type, const char *input, void **result) { +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(type->type == DYN_TYPE_COMPLEX); int status = 0; @@ -19,133 +34,379 @@ int json_deserialize(dyn_type *type, const char *input, void **result) { json_t *root = json_loads(input, JSON_DECODE_ANY, &error); if (root != NULL) { - status = json_serializer_createObject(type, root, result); + if (json_is_object(root)) { + status = jsonSerializer_createObject(type, root, result); + } else { + status = ERROR; + LOG_ERROR("Error expected root element to be an object"); + } json_decref(root); } else { - status = 1; - printf("JSON_SERIALIZER: error parsing json input '%s'. Error is %s\n", input, error.text); + status = ERROR; + LOG_ERROR("Error parsing json input '%s'. Error is %s\n", input, error.text); } return status; } -static int json_serializer_createObject(dyn_type *type, json_t *object, void **result) { +static int jsonSerializer_createObject(dyn_type *type, json_t *object, void **result) { assert(object != NULL); - int status = 0; + int status = OK; void *inst = NULL; status = dynType_alloc(type, &inst); - if (status == 0) { + if (status == OK) { assert(inst != NULL); - status = json_serializer_writeObject(type, object, inst); - } else { - //TODO destroy + status = jsonSerializer_parseObject(type, object, inst); + + if (status != OK) { + dynType_free(type, inst); + } } - if (status == 0) { + if (status == OK) { *result = inst; - } + } return status; } - -static int json_serializer_writeObject(dyn_type *type, json_t *object, void *inst) { + +static int jsonSerializer_parseObject(dyn_type *type, json_t *object, void *inst) { assert(object != NULL); int status = 0; json_t *value; const char *key; - if (status == 0) { - json_object_foreach(object, key, value) { - json_serializer_writeObjectMember(type, key, value, inst); + json_object_foreach(object, key, value) { + status = jsonSerializer_parseObjectMember(type, key, value, inst); + if (status != OK) { + break; } - } else { - status = 1; - printf("JSON_SERIALIZER: Error allocating memory\n"); } return status; } -static void json_serializer_writeObjectMember(dyn_type *type, const char *name, json_t *val, void *inst) { - //TODO rename to complex. write generic write - int status = 0; +static int jsonSerializer_parseObjectMember(dyn_type *type, const char *name, json_t *val, void *inst) { + int status = OK; int index = dynType_complex_indexForName(type, name); - char charType = dynType_complex_descriptorTypeAt(type, index); void *valp = NULL; + dyn_type *valType = NULL; + status = dynType_complex_valLocAt(type, index, inst, &valp); - //TODO check status + if (status == OK ) { + status = dynType_complex_dynTypeAt(type, index, &valType); + } - float *f; - double *d; - char *c; - short *s; - int *i; - long *l; - dyn_type *nested; + if (status == OK) { + status = jsonSerializer_parseAny(valType, valp, val); + } + + return status; +} - switch (charType) { +static int jsonSerializer_parseAny(dyn_type *type, void *loc, json_t *val) { + int status = OK; + + dyn_type *subType = NULL; + + float *f; //F + double *d; //D + char *b; //B + int *n; //N + int16_t *s; //S + int32_t *i; //I + int64_t *l; //J + uint16_t *us; //s + uint32_t *ui; //i + uint64_t *ul; //j + + switch (type->descriptor) { case 'F' : - f = valp; - *f = json_real_value(val); + f = loc; + *f = (float) json_real_value(val); break; case 'D' : - d = valp; + d = loc; *d = json_real_value(val); break; + case 'N' : + n = loc; + *n = (int) json_real_value(val); + break; case 'B' : - c = valp; - *c = json_integer_value(val); + b = loc; + *b = (char) json_integer_value(val); break; case 'S' : - s = valp; - *s = json_integer_value(val); + s = loc; + *s = (int16_t) json_integer_value(val); break; case 'I' : - i = valp; - *i = json_integer_value(val); + i = loc; + *i = (int32_t) json_integer_value(val); break; case 'J' : - l = valp; - *l = json_integer_value(val); + l = loc; + *l = (int64_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 '[' : - status = dynType_complex_dynTypeAt(type, index, &nested); - //TODO check status - //TODO json_serializer_writeSequence(val, val, valp); + 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 '{' : - status = dynType_complex_dynTypeAt(type, index, &nested); - //TODO check status - status = json_serializer_writeObject(nested, val, valp); - //TODO check status + if (status == OK) { + status = jsonSerializer_parseObject(type, val, loc); + } + break; + case '*' : + status = dynType_typedPointer_getTypedType(type, &subType); + if (status == OK) { + status = jsonSerializer_createObject(subType, val, (void **)loc); + } + break; + case 'P' : + status = ERROR; + LOG_WARNING("Untyped pointer are not supported for serialization"); break; default : - printf("JSON_SERIALIZER: error provided type '%c' not supported\n", charType); - printf("Skipping\n"); + status = ERROR; + LOG_ERROR("Error provided type '%c' not supported for JSON\n", type->descriptor); + break; } -} -static void json_serializer_writeSequence(json_t *array, dyn_type *seq, void *seqLoc) { + return status; +} + +static int jsonSerializer_parseSequence(dyn_type *seq, json_t *array, void *seqLoc) { assert(dynType_type(seq) == DYN_TYPE_SEQUENCE); - size_t size = json_array_size(array); - //char seqType = dynType_sequence_elementSchemaType(seq); + int status = OK; + size_t size = json_array_size(array); void *buf = NULL; - dynType_sequence_alloc(seq, seqLoc, size, &buf); //seq is already allocated. only need to allocate the buf - - //assuming int - int32_t i; - int index; - json_t *val; - json_array_foreach(array, index, val) { - i = json_number_value(val); - dynType_sequence_append(seq, seqLoc, &i); + LOG_DEBUG("Allocating sequence with capacity %zu", size); + status = dynType_sequence_alloc(seq, seqLoc, (int) size, &buf); + + 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", valLoc); + + if (status == OK) { + status = jsonSerializer_parseAny(itemType, valLoc, val); + if (status != OK) { + break; + } + } + } } + + return status; } -int json_serialize(dyn_type *type, void *input, char **output, size_t *size) { - return 0; +int jsonSerializer_serialize(dyn_type *type, void *input, char **output) { + int status = OK; + + json_t *root = NULL; + status = jsonSerializer_writeAny(type, input, &root); + + if (status == OK) { + *output = json_dumps(root, JSON_COMPACT); + json_decref(root); + } + + return status; } + +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; + + float *f; //F + double *d; //D + char *b; //B + int *n; //N + int16_t *s; //S + int32_t *i; //I + int64_t *l; //J + uint16_t *us; //s + uint32_t *ui; //i + uint64_t *ul; //j + + switch (descriptor) { + 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 '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(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_new(array, 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(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); + } + + if (status != OK) { + break; + } + } + } + + if (status == OK && val != NULL) { + *out = val; + } + + return status; +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/celix/blob/24d13f2e/remote_services/dynamic_function_interface/json_serializer.h ---------------------------------------------------------------------- diff --git a/remote_services/dynamic_function_interface/json_serializer.h b/remote_services/dynamic_function_interface/json_serializer.h index 6b42244..eb2e629 100644 --- a/remote_services/dynamic_function_interface/json_serializer.h +++ b/remote_services/dynamic_function_interface/json_serializer.h @@ -4,9 +4,13 @@ #ifndef __JSON_SERIALIZER_H_ #define __JSON_SERIALIZER_H_ +#include "dfi_log_util.h" #include "dyn_type.h" -int json_deserialize(dyn_type *type, const char *input, void **result); -int json_serialize(dyn_type *type, void *input, char **output, size_t *size); +//logging +DFI_SETUP_LOG_HEADER(jsonSerializer); + +int jsonSerializer_deserialize(dyn_type *type, const char *input, void **result); +int jsonSerializer_serialize(dyn_type *type, void *input, char **output); #endif http://git-wip-us.apache.org/repos/asf/celix/blob/24d13f2e/remote_services/dynamic_function_interface/tst/json_serializer_tests.cpp ---------------------------------------------------------------------- diff --git a/remote_services/dynamic_function_interface/tst/json_serializer_tests.cpp b/remote_services/dynamic_function_interface/tst/json_serializer_tests.cpp index cd61e6e..d5c76ea 100644 --- a/remote_services/dynamic_function_interface/tst/json_serializer_tests.cpp +++ b/remote_services/dynamic_function_interface/tst/json_serializer_tests.cpp @@ -46,9 +46,13 @@ struct example1 { float e; //4 }; -static void print_example1(void *data) { +static void check_example1(void *data) { struct example1 *ex = (struct example1 *)data; - printf("example1: a:%f, b:%li, c:%i, d:%i, e:%f\n", ex->a, (long)ex->b, ex->c, ex->d, ex->e); + CHECK_EQUAL(1.0, ex->a); + CHECK_EQUAL(22, ex->b); + CHECK_EQUAL(32, ex->c); + CHECK_EQUAL(42, ex->d); + CHECK_EQUAL(4.4f, ex->e); } /*********** example 2 ************************/ @@ -72,9 +76,14 @@ struct example2 { double double2; //5 }; -static void print_example2(void *data) { +static void check_example2(void *data) { struct example2 *ex = (struct example2 *)data; - printf("example2: byte:%i, long1:%li, long2:%li, double1:%f, float1:%f, double2:%f\n", ex->byte, (long)ex->long1, (long)ex->long2, ex->double1, ex->float1, ex->double2); + CHECK_EQUAL(42, ex->byte); + CHECK_EQUAL(232, ex->long1); + CHECK_EQUAL(242, ex->long2); + CHECK_EQUAL(4.2, ex->double1); + CHECK_EQUAL(3.2f, ex->float1); + CHECK_EQUAL(4.4, ex->double2); } @@ -88,24 +97,22 @@ const char *example3_input = "{ \ struct example3 { struct { - uint32_t _cap; - uint32_t _len; + uint32_t cap; + uint32_t len; int32_t *buf; } numbers; }; -static void print_example3(void *data) { +static void check_example3(void *data) { struct example3 *ex = (struct example3 *)data; - printf("example3: numbers length is %u and cap is %u and pointer buf is %p\n", ex->numbers._len, ex->numbers._cap, ex->numbers.buf); - int i; - for (i = 0; i < ex->numbers._len; i += 1) { - printf("\telement %i : %i\n", i, ex->numbers.buf[i]); - } + CHECK_EQUAL(3, ex->numbers.len); + CHECK_EQUAL(22, ex->numbers.buf[0]); + CHECK_EQUAL(32, ex->numbers.buf[1]); + CHECK_EQUAL(42, ex->numbers.buf[2]); } /*********** example 4 ************************/ /** structs within a struct (by reference)*******/ -//TODO think about references in descriptor e.g "{Lleaf;Lleaf; left right}\nleaf{IDD index val1 val2}" const char *example4_descriptor = "{{IDD index val1 val2}{IDD index val1 val2} left right}"; static const char *example4_input = "{ \ @@ -113,23 +120,84 @@ static const char *example4_input = "{ \ \"right\" : {\"index\":2, \"val1\":5.0, \"val2\":4.0 } \ }"; -struct leaf { +struct ex4_leaf { int32_t index; double val1; double val2; }; struct example4 { - struct leaf left; - struct leaf right; + struct ex4_leaf left; + struct ex4_leaf right; }; -static void print_example4(void *data) { +static void check_example4(void *data) { struct example4 *ex = (struct example4 *)data; - printf("example4: left { index:%i, val1:%f, val2:%f }, right { index;%i, val1:%f, val2:%f }\n", ex->left.index, ex->left.val1, ex->left.val2, ex->right.index, ex->right.val1, ex->right.val2); + CHECK_EQUAL(1, ex->left.index); + CHECK_EQUAL(1.0, ex->left.val1); + CHECK_EQUAL(2.0, ex->left.val2); + CHECK_EQUAL(2, ex->right.index); + CHECK_EQUAL(5.0, ex->right.val1); + CHECK_EQUAL(4.0, ex->right.val2); +} + + +/*********** example 4 ************************/ +/** structs within a struct (by reference)*******/ +const char *example5_descriptor = "Tleaf={ts name age};Tnode={Lnode;Lnode;Lleaf; left right value};{Lnode; head}"; + +static const char *example5_input = "{ \ + \"head\" : {\ + \"left\" : {\ + \"value\" : {\ + \"name\" : \"John\",\ + \"age\" : 44 \ + }\ + },\ + \"right\" : {\ + \"value\" : {\ + \"name\" : \"Peter\", \ + \"age\" : 55 \ + }\ + }\ + }\ +}"; + +struct leaf { + const char *name; + uint16_t age; +}; + +struct node { + struct node *left; + struct node *right; + struct leaf *value; +}; + +struct example5 { + struct node *head; +}; + +static void check_example5(void *data) { + struct example5 *ex = (struct example5 *)data; + CHECK_TRUE(ex->head != NULL); + + CHECK(ex->head->left != NULL); + CHECK(ex->head->left->value != NULL); + STRCMP_EQUAL("John", ex->head->left->value->name); + CHECK_EQUAL(44, ex->head->left->value->age); + CHECK(ex->head->left->left == NULL); + CHECK(ex->head->left->right == NULL); + + CHECK(ex->head->right != NULL); + CHECK(ex->head->right->value != NULL); + STRCMP_EQUAL("Peter", ex->head->right->value->name); + CHECK_EQUAL(55, ex->head->right->value->age); + CHECK(ex->head->right->left == NULL); + CHECK(ex->head->right->right == NULL); } -static void tests() { +static void parseTests(void) { printf("Starting json serializer tests\n"); dyn_type *type; void *inst; @@ -139,47 +207,176 @@ static void tests() { inst = NULL; rc = dynType_parseWithStr(example1_descriptor, NULL, NULL, &type); CHECK_EQUAL(0, rc); - rc = json_deserialize(type, example1_input, &inst); + rc = jsonSerializer_deserialize(type, example1_input, &inst); CHECK_EQUAL(0, rc); - print_example1(inst); - printf("--\n\n"); - + check_example1(inst); type = NULL; inst = NULL; rc = dynType_parseWithStr(example2_descriptor, NULL, NULL, &type); CHECK_EQUAL(0, rc); - rc = json_deserialize(type, example2_input, &inst); + rc = jsonSerializer_deserialize(type, example2_input, &inst); CHECK_EQUAL(0, rc); - print_example2(inst); - printf("--\n\n"); + check_example2(inst); type = NULL; inst = NULL; rc = dynType_parseWithStr(example3_descriptor, NULL, NULL, &type); CHECK_EQUAL(0, rc); - rc = json_deserialize(type, example3_input, &inst); + rc = jsonSerializer_deserialize(type, example3_input, &inst); CHECK_EQUAL(0, rc); - print_example3(inst); + check_example3(inst); type = NULL; inst = NULL; rc = dynType_parseWithStr(example4_descriptor, NULL, NULL, &type); CHECK_EQUAL(0, rc); - rc = json_deserialize(type, example4_input, &inst); + rc = jsonSerializer_deserialize(type, example4_input, &inst); + CHECK_EQUAL(0, rc); + check_example4(inst); + + type = NULL; + inst = NULL; + rc = dynType_parseWithStr(example5_descriptor, NULL, NULL, &type); + CHECK_EQUAL(0, rc); + rc = jsonSerializer_deserialize(type, example5_input, &inst); + CHECK_EQUAL(0, rc); + check_example5(inst); +} + +const char *write_example1_descriptor = "{BSIJsijFDN a b c d e f g h i j}"; + +struct write_example1 { + char a; + int16_t b; + int32_t c; + int64_t d; + uint16_t e; + uint32_t f; + uint64_t g; + float h; + double i; + int j; +}; + +void writeTest1(void) { + struct write_example1 ex1 = {.a=1, .b=2, .c=3, .d=4, .e=5, .f=6, .g=7, .h=8.8f, .i=9.9, .j=10}; + dyn_type *type = NULL; + char *result = NULL; + int rc = dynType_parseWithStr(write_example1_descriptor, "ex1", NULL, &type); + CHECK_EQUAL(0, rc); + rc = jsonSerializer_serialize(type, &ex1, &result); + CHECK_EQUAL(0, rc); + STRCMP_CONTAINS("\"a\":1", result); + STRCMP_CONTAINS("\"b\":2", result); + STRCMP_CONTAINS("\"c\":3", result); + STRCMP_CONTAINS("\"d\":4", result); + STRCMP_CONTAINS("\"e\":5", result); + STRCMP_CONTAINS("\"f\":6", result); + STRCMP_CONTAINS("\"g\":7", result); + STRCMP_CONTAINS("\"h\":8.8", result); + STRCMP_CONTAINS("\"i\":9.9", result); + STRCMP_CONTAINS("\"j\":10", result); + //printf("example 1 result: '%s'\n", result); +} + +const char *write_example2_descriptor = "{*{JJ a b}{SS c d} sub1 sub2}"; + +struct write_example2_sub { + int64_t a; + int64_t b; +}; + +struct write_example2 { + struct write_example2_sub *sub1; + struct { + int16_t c; + int16_t d; + } sub2; +}; + +void writeTest2(void) { + struct write_example2_sub sub1 = { .a = 1, .b = 2 }; + struct write_example2 ex = { .sub1 = &sub1 }; + ex.sub2.c = 3; + ex.sub2.d = 4; + + dyn_type *type = NULL; + char *result = NULL; + int rc = dynType_parseWithStr(write_example2_descriptor, "ex2", NULL, &type); + CHECK_EQUAL(0, rc); + rc = jsonSerializer_serialize(type, &ex, &result); + CHECK_EQUAL(0, rc); + STRCMP_CONTAINS("\"a\":1", result); + STRCMP_CONTAINS("\"b\":2", result); + STRCMP_CONTAINS("\"c\":3", result); + STRCMP_CONTAINS("\"d\":4", result); + //printf("example 2 result: '%s'\n", result); +} + +const char *write_example3_descriptor = "Tperson={ti name age};[Lperson;"; + +struct write_example3_person { + const char *name; + uint32_t age; +}; + +struct write_example3 { + uint32_t cap; + uint32_t len; + struct write_example3_person **buf; +}; + +void writeTest3(void) { + struct write_example3_person p1 = {.name = "John", .age = 33}; + struct write_example3_person p2 = {.name = "Peter", .age = 44}; + struct write_example3_person p3 = {.name = "Carol", .age = 55}; + struct write_example3_person p4 = {.name = "Elton", .age = 66}; + struct write_example3 seq; + seq.buf = (struct write_example3_person **) calloc(4, sizeof(void *)); + seq.len = seq.cap = 4; + seq.buf[0] = &p1; + seq.buf[1] = &p2; + seq.buf[2] = &p3; + seq.buf[3] = &p4; + + dyn_type *type = NULL; + char *result = NULL; + int rc = dynType_parseWithStr(write_example3_descriptor, "ex3", NULL, &type); + CHECK_EQUAL(0, rc); + rc = jsonSerializer_serialize(type, &seq, &result); CHECK_EQUAL(0, rc); - print_example4(inst); + STRCMP_CONTAINS("\"age\":33", result); + STRCMP_CONTAINS("\"age\":44", result); + STRCMP_CONTAINS("\"age\":55", result); + STRCMP_CONTAINS("\"age\":66", result); + //printf("example 3 result: '%s'\n", result); } + } TEST_GROUP(JsonSerializerTests) { void setup() { - dynType_logSetup(stdLog, NULL, 3); - dynCommon_logSetup(stdLog, NULL, 3); + int lvl = 3; + dynCommon_logSetup(stdLog, NULL, lvl); + dynType_logSetup(stdLog, NULL,lvl); + jsonSerializer_logSetup(stdLog, NULL, lvl); } }; -TEST(JsonSerializerTests, Test1) { +TEST(JsonSerializerTests, ParseTests) { //TODO split up - tests(); + parseTests(); +} + +TEST(JsonSerializerTests, WriteTest1) { + writeTest1(); +} + +TEST(JsonSerializerTests, WriteTest2) { + writeTest2(); +} + +TEST(JsonSerializerTests, WriteTest3) { + writeTest3(); }