123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541 |
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- *
- * Copyright (c) 2019 Fraunhofer IOSB (Author: Lukas Meling)
- */
- #include "ua_types.h"
- #include "ua_types_generated_handling.h"
- #include "ua_types_encoding_json.h"
- #include "ua_pubsub_networkmessage.h"
- /* Json keys for dsm */
- const char * UA_DECODEKEY_MESSAGES = ("Messages");
- const char * UA_DECODEKEY_MESSAGETYPE = ("MessageType");
- const char * UA_DECODEKEY_MESSAGEID = ("MessageId");
- const char * UA_DECODEKEY_PUBLISHERID = ("PublisherId");
- const char * UA_DECODEKEY_DATASETCLASSID = ("DataSetClassId");
- /* Json keys for dsm */
- const char * UA_DECODEKEY_DATASETWRITERID = ("DataSetWriterId");
- const char * UA_DECODEKEY_SEQUENCENUMBER = ("SequenceNumber");
- const char * UA_DECODEKEY_METADATAVERSION = ("MetaDataVersion");
- const char * UA_DECODEKEY_TIMESTAMP = ("Timestamp");
- const char * UA_DECODEKEY_DSM_STATUS = ("Status");
- const char * UA_DECODEKEY_PAYLOAD = ("Payload");
- const char * UA_DECODEKEY_DS_TYPE = ("Type");
- /* -- json encoding/decoding -- */
- static UA_StatusCode writeJsonKey_UA_String(CtxJson *ctx, UA_String *in){
- UA_STACKARRAY(char, out, in->length + 1);
- memcpy(out, in->data, in->length);
- out[in->length] = 0;
- return writeJsonKey(ctx, out);
- }
- static UA_StatusCode
- UA_DataSetMessage_encodeJson_internal(const UA_DataSetMessage* src, UA_UInt16 dataSetWriterId,
- CtxJson *ctx){
- status rv = writeJsonObjStart(ctx);
- /* DataSetWriterId */
- rv |= writeJsonKey(ctx, UA_DECODEKEY_DATASETWRITERID);
- rv |= encodeJsonInternal(&dataSetWriterId, &UA_TYPES[UA_TYPES_UINT16], ctx);
- if(rv != UA_STATUSCODE_GOOD)
- return rv;
- /* DataSetMessageSequenceNr */
- if(src->header.dataSetMessageSequenceNrEnabled) {
- rv |= writeJsonKey(ctx, UA_DECODEKEY_SEQUENCENUMBER);
- rv |= encodeJsonInternal(&(src->header.dataSetMessageSequenceNr),
- &UA_TYPES[UA_TYPES_UINT16], ctx);
- if(rv != UA_STATUSCODE_GOOD)
- return rv;
- }
- /* MetaDataVersion */
- if(src->header.configVersionMajorVersionEnabled || src->header.configVersionMinorVersionEnabled) {
- rv |= writeJsonKey(ctx, UA_DECODEKEY_METADATAVERSION);
- UA_ConfigurationVersionDataType cvd;
- cvd.majorVersion = src->header.configVersionMajorVersion;
- cvd.minorVersion = src->header.configVersionMinorVersion;
- rv |= encodeJsonInternal(&cvd, &UA_TYPES[UA_TYPES_CONFIGURATIONVERSIONDATATYPE], ctx);
- if(rv != UA_STATUSCODE_GOOD)
- return rv;
- }
- /* Timestamp */
- if(src->header.timestampEnabled) {
- rv |= writeJsonKey(ctx, UA_DECODEKEY_TIMESTAMP);
- rv |= encodeJsonInternal(&(src->header.timestamp), &UA_TYPES[UA_TYPES_DATETIME], ctx);
- if(rv != UA_STATUSCODE_GOOD)
- return rv;
- }
- /* Status */
- if(src->header.statusEnabled) {
- rv |= writeJsonKey(ctx, UA_DECODEKEY_DSM_STATUS);
- rv |= encodeJsonInternal(&(src->header.status), &UA_TYPES[UA_TYPES_STATUSCODE], ctx);
- if(rv != UA_STATUSCODE_GOOD)
- return rv;
- }
- rv |= writeJsonKey(ctx, UA_DECODEKEY_PAYLOAD);
- rv |= writeJsonObjStart(ctx);
- /* TODO: currently no difference between delta and key frames. Own
- * dataSetMessageType for json?. If the field names are not defined, write
- * out empty field names. */
- if(src->header.dataSetMessageType == UA_DATASETMESSAGE_DATAKEYFRAME) {
- if(src->header.fieldEncoding == UA_FIELDENCODING_VARIANT) {
- /* KEYFRAME VARIANT */
- for (UA_UInt16 i = 0; i < src->data.keyFrameData.fieldCount; i++) {
- if(src->data.keyFrameData.fieldNames)
- rv |= writeJsonKey_UA_String(ctx, &src->data.keyFrameData.fieldNames[i]);
- else
- rv |= writeJsonKey(ctx, "");
- rv |= encodeJsonInternal(&(src->data.keyFrameData.dataSetFields[i].value),
- &UA_TYPES[UA_TYPES_VARIANT], ctx);
- if(rv != UA_STATUSCODE_GOOD)
- return rv;
- }
- } else if(src->header.fieldEncoding == UA_FIELDENCODING_RAWDATA) {
- return UA_STATUSCODE_BADNOTIMPLEMENTED;
- } else if(src->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) {
- /* KEYFRAME DATAVALUE */
- for (UA_UInt16 i = 0; i < src->data.keyFrameData.fieldCount; i++) {
- if(src->data.keyFrameData.fieldNames)
- rv |= writeJsonKey_UA_String(ctx, &src->data.keyFrameData.fieldNames[i]);
- else
- rv |= writeJsonKey(ctx, "");
- rv |= encodeJsonInternal(&src->data.keyFrameData.dataSetFields[i],
- &UA_TYPES[UA_TYPES_DATAVALUE], ctx);
- if(rv != UA_STATUSCODE_GOOD)
- return rv;
- }
- }
- }else if(src->header.dataSetMessageType == UA_DATASETMESSAGE_DATADELTAFRAME){
- return UA_STATUSCODE_BADNOTSUPPORTED;
- }
- rv |= writeJsonObjEnd(ctx); /* Payload */
- rv |= writeJsonObjEnd(ctx); /* DataSetMessage */
- return rv;
- }
- static UA_StatusCode
- UA_NetworkMessage_encodeJson_internal(const UA_NetworkMessage* src, CtxJson *ctx) {
- status rv = UA_STATUSCODE_GOOD;
- /* currently only ua-data is supported */
- if(src->networkMessageType == UA_NETWORKMESSAGE_DATASET) {
- writeJsonObjStart(ctx);
- /* Table 91 – JSON NetworkMessage Definition
- * MessageId | String | A globally unique identifier for the message.
- * This value is mandatory. */
- rv |= writeJsonKey(ctx, UA_DECODEKEY_MESSAGEID);
- /* If a messageId is given use it, otherwise generate a GUID(-string).
- * MessageId is always decoded as a string. */
- if(src->messageIdEnabled){
- rv |= encodeJsonInternal(&src->messageId, &UA_TYPES[UA_TYPES_STRING], ctx);
- } else {
- UA_Guid guid = UA_Guid_random();
- rv |= encodeJsonInternal(&guid, &UA_TYPES[UA_TYPES_GUID], ctx);
- }
- /* MessageType */
- rv |= writeJsonKey(ctx, UA_DECODEKEY_MESSAGETYPE);
- UA_String s = UA_STRING("ua-data");
- rv |= encodeJsonInternal(&s, &UA_TYPES[UA_TYPES_STRING], ctx);
- /* PublisherId */
- if(src->publisherIdEnabled) {
- rv = writeJsonKey(ctx, UA_DECODEKEY_PUBLISHERID);
- switch (src->publisherIdType) {
- case UA_PUBLISHERDATATYPE_BYTE:
- rv |= encodeJsonInternal(&src->publisherId.publisherIdByte,
- &UA_TYPES[UA_TYPES_BYTE], ctx);
- break;
- case UA_PUBLISHERDATATYPE_UINT16:
- rv |= encodeJsonInternal(&src->publisherId.publisherIdUInt16,
- &UA_TYPES[UA_TYPES_UINT16], ctx);
- break;
- case UA_PUBLISHERDATATYPE_UINT32:
- rv |= encodeJsonInternal(&src->publisherId.publisherIdUInt32,
- &UA_TYPES[UA_TYPES_UINT32], ctx);
- break;
- case UA_PUBLISHERDATATYPE_UINT64:
- rv |= encodeJsonInternal(&src->publisherId.publisherIdUInt64,
- &UA_TYPES[UA_TYPES_UINT64], ctx);
- break;
- case UA_PUBLISHERDATATYPE_STRING:
- rv |= encodeJsonInternal(&src->publisherId.publisherIdString,
- &UA_TYPES[UA_TYPES_STRING], ctx);
- break;
- }
- }
- if(rv != UA_STATUSCODE_GOOD)
- return rv;
- /* DataSetClassId */
- if(src->dataSetClassIdEnabled) {
- rv |= writeJsonKey(ctx, UA_DECODEKEY_DATASETCLASSID);
- rv |= encodeJsonInternal(&src->dataSetClassId, &UA_TYPES[UA_TYPES_GUID], ctx);
- if(rv != UA_STATUSCODE_GOOD)
- return rv;
- }
- /* Payload: DataSetMessages */
- UA_Byte count = src->payloadHeader.dataSetPayloadHeader.count;
- if(count > 0){
- UA_UInt16 *dataSetWriterIds = src->payloadHeader.dataSetPayloadHeader.dataSetWriterIds;
- if(!dataSetWriterIds){
- return UA_STATUSCODE_BADENCODINGERROR;
- }
- rv |= writeJsonKey(ctx, UA_DECODEKEY_MESSAGES);
- rv |= writeJsonArrStart(ctx); /* start array */
- for (UA_UInt16 i = 0; i < count; i++) {
- writeJsonCommaIfNeeded(ctx);
- rv |= UA_DataSetMessage_encodeJson_internal(&src->payload.dataSetPayload.dataSetMessages[i],
- dataSetWriterIds[i], ctx);
- if(rv != UA_STATUSCODE_GOOD)
- return rv;
- /* comma is needed if more dsm are present */
- ctx->commaNeeded[ctx->depth] = true;
- }
- rv |= writeJsonArrEnd(ctx); /* end array */
- }
- rv |= writeJsonObjEnd(ctx);
- } else {
- /* no discovery message implemented */
- rv = UA_STATUSCODE_BADNOTIMPLEMENTED;
- }
- return rv;
- }
- UA_StatusCode
- UA_NetworkMessage_encodeJson(const UA_NetworkMessage *src,
- UA_Byte **bufPos, const UA_Byte **bufEnd, UA_String *namespaces,
- size_t namespaceSize, UA_String *serverUris,
- size_t serverUriSize, UA_Boolean useReversible) {
- /* Set up the context */
- CtxJson ctx;
- memset(&ctx, 0, sizeof(ctx));
- ctx.pos = *bufPos;
- ctx.end = *bufEnd;
- ctx.depth = 0;
- ctx.namespaces = namespaces;
- ctx.namespacesSize = namespaceSize;
- ctx.serverUris = serverUris;
- ctx.serverUrisSize = serverUriSize;
- ctx.useReversible = useReversible;
- ctx.calcOnly = false;
- status ret = UA_NetworkMessage_encodeJson_internal(src, &ctx);
- *bufPos = ctx.pos;
- *bufEnd = ctx.end;
- return ret;
- }
- size_t
- UA_NetworkMessage_calcSizeJson(const UA_NetworkMessage *src,
- UA_String *namespaces, size_t namespaceSize,
- UA_String *serverUris, size_t serverUriSize,
- UA_Boolean useReversible){
- /* Set up the context */
- CtxJson ctx;
- memset(&ctx, 0, sizeof(ctx));
- ctx.pos = 0;
- ctx.end = (const UA_Byte*)(uintptr_t)SIZE_MAX;
- ctx.depth = 0;
- ctx.namespaces = namespaces;
- ctx.namespacesSize = namespaceSize;
- ctx.serverUris = serverUris;
- ctx.serverUrisSize = serverUriSize;
- ctx.useReversible = useReversible;
- ctx.calcOnly = true;
- status ret = UA_NetworkMessage_encodeJson_internal(src, &ctx);
- if(ret != UA_STATUSCODE_GOOD)
- return 0;
- return (size_t)ctx.pos;
- }
- /* decode json */
- static status
- MetaDataVersion_decodeJsonInternal(void* cvd, const UA_DataType *type, CtxJson *ctx,
- ParseCtx *parseCtx, UA_Boolean moveToken){
- return decodeJsonInternal(cvd, &UA_TYPES[UA_TYPES_CONFIGURATIONVERSIONDATATYPE],
- ctx, parseCtx, UA_TRUE);
- }
- static status
- DataSetPayload_decodeJsonInternal(void* dsmP, const UA_DataType *type, CtxJson *ctx,
- ParseCtx *parseCtx, UA_Boolean moveToken) {
- UA_DataSetMessage* dsm = (UA_DataSetMessage*)dsmP;
- dsm->header.dataSetMessageValid = UA_TRUE;
- if(isJsonNull(ctx, parseCtx)) {
- parseCtx->index++;
- return UA_STATUSCODE_GOOD;
- }
- size_t length = (size_t)parseCtx->tokenArray[parseCtx->index].size;
- UA_String *fieldNames = (UA_String*)UA_calloc(length, sizeof(UA_String));
- dsm->data.keyFrameData.fieldNames = fieldNames;
- dsm->data.keyFrameData.fieldCount = (UA_UInt16)length;
- dsm->data.keyFrameData.dataSetFields = (UA_DataValue *)
- UA_Array_new(dsm->data.keyFrameData.fieldCount, &UA_TYPES[UA_TYPES_DATAVALUE]);
- status ret = UA_STATUSCODE_GOOD;
- parseCtx->index++; // We go to first Object key!
- /* iterate over the key/value pairs in the object. Keys are stored in fieldnames. */
- for(size_t i = 0; i < length; ++i) {
- ret = getDecodeSignature(UA_TYPES_STRING)(&fieldNames[i], type, ctx, parseCtx, UA_TRUE);
- if(ret != UA_STATUSCODE_GOOD)
- return ret;
- //TODO: Is field value a variant or datavalue? Current check if type and body present.
- size_t searchResult = 0;
- status foundType = lookAheadForKey("Type", ctx, parseCtx, &searchResult);
- status foundBody = lookAheadForKey("Body", ctx, parseCtx, &searchResult);
- if(foundType == UA_STATUSCODE_GOOD && foundBody == UA_STATUSCODE_GOOD){
- dsm->header.fieldEncoding = UA_FIELDENCODING_VARIANT;
- ret = getDecodeSignature(UA_TYPES_VARIANT)
- (&dsm->data.keyFrameData.dataSetFields[i].value, type, ctx, parseCtx, UA_TRUE);
- dsm->data.keyFrameData.dataSetFields[i].hasValue = UA_TRUE;
- } else {
- dsm->header.fieldEncoding = UA_FIELDENCODING_DATAVALUE;
- ret = getDecodeSignature(UA_TYPES_DATAVALUE)
- (&dsm->data.keyFrameData.dataSetFields[i], type, ctx, parseCtx, UA_TRUE);
- dsm->data.keyFrameData.dataSetFields[i].hasValue = UA_TRUE;
- }
- if(ret != UA_STATUSCODE_GOOD)
- return ret;
- }
- return ret;
- }
- static status
- DatasetMessage_Payload_decodeJsonInternal(UA_DataSetMessage* dsm, const UA_DataType *type,
- CtxJson *ctx, ParseCtx *parseCtx, UA_Boolean moveToken) {
- UA_ConfigurationVersionDataType cvd;
- UA_UInt16 dataSetWriterId; /* the id is currently not processed */
- dsm->header.fieldEncoding = UA_FIELDENCODING_DATAVALUE;
- DecodeEntry entries[6] = {
- {UA_DECODEKEY_DATASETWRITERID, &dataSetWriterId,
- getDecodeSignature(UA_TYPES_UINT16), false, NULL},
- {UA_DECODEKEY_SEQUENCENUMBER, &dsm->header.dataSetMessageSequenceNr,
- getDecodeSignature(UA_TYPES_UINT16), false, NULL},
- {UA_DECODEKEY_METADATAVERSION, &cvd,
- &MetaDataVersion_decodeJsonInternal, false, NULL},
- {UA_DECODEKEY_TIMESTAMP, &dsm->header.timestamp,
- getDecodeSignature(UA_TYPES_DATETIME), false, NULL},
- {UA_DECODEKEY_DSM_STATUS, &dsm->header.status,
- getDecodeSignature(UA_TYPES_UINT16), false, NULL},
- {UA_DECODEKEY_PAYLOAD, dsm,
- &DataSetPayload_decodeJsonInternal, false, NULL}
- };
- status ret = decodeFields(ctx, parseCtx, entries, 6, NULL);
- if(ret != UA_STATUSCODE_GOOD || !entries[0].found){
- /* no dataSetwriterid. Is mandatory. Abort. */
- return UA_STATUSCODE_BADDECODINGERROR;
- }else{
- if(parseCtx->custom != NULL){
- UA_UInt16* dataSetWriterIdsArray = (UA_UInt16*)parseCtx->custom;
- if(*parseCtx->currentCustomIndex < parseCtx->numCustom){
- dataSetWriterIdsArray[*parseCtx->currentCustomIndex] = dataSetWriterId;
- (*parseCtx->currentCustomIndex)++;
- }else{
- return UA_STATUSCODE_BADDECODINGERROR;
- }
- }else{
- return UA_STATUSCODE_BADDECODINGERROR;
- }
- }
- dsm->header.dataSetMessageSequenceNrEnabled = entries[1].found;
- dsm->header.configVersionMajorVersion = cvd.majorVersion;
- dsm->header.configVersionMinorVersion = cvd.minorVersion;
- dsm->header.configVersionMajorVersionEnabled = entries[2].found;
- dsm->header.configVersionMinorVersionEnabled = entries[2].found;
- dsm->header.timestampEnabled = entries[3].found;
- dsm->header.statusEnabled = entries[4].found;
- if(!entries[5].found){
- /* No payload found */
- return UA_STATUSCODE_BADDECODINGERROR;
- }
- dsm->header.dataSetMessageType = UA_DATASETMESSAGE_DATAKEYFRAME;
- dsm->header.picoSecondsIncluded = UA_FALSE;
- dsm->header.dataSetMessageValid = UA_TRUE;
- dsm->header.fieldEncoding = UA_FIELDENCODING_VARIANT;
- return ret;
- }
- static status
- DatasetMessage_Array_decodeJsonInternal(void *UA_RESTRICT dst, const UA_DataType *type,
- CtxJson *ctx, ParseCtx *parseCtx, UA_Boolean moveToken) {
- /* Array! */
- if(getJsmnType(parseCtx) != JSMN_ARRAY)
- return UA_STATUSCODE_BADDECODINGERROR;
- size_t length = (size_t)parseCtx->tokenArray[parseCtx->index].size;
- /* Return early for empty arrays */
- if(length == 0)
- return UA_STATUSCODE_GOOD;
- /* Allocate memory */
- UA_DataSetMessage *dsm = (UA_DataSetMessage*)UA_calloc(length, sizeof(UA_DataSetMessage));
- if(dsm == NULL)
- return UA_STATUSCODE_BADOUTOFMEMORY;
- /* Copy new Pointer do dest */
- memcpy(dst, &dsm, sizeof(void*));
- /* We go to first Array member! */
- parseCtx->index++;
- status ret = UA_STATUSCODE_BADDECODINGERROR;
- /* Decode array members */
- for(size_t i = 0; i < length; ++i) {
- ret = DatasetMessage_Payload_decodeJsonInternal(&dsm[i], NULL, ctx, parseCtx, UA_TRUE);
- if(ret != UA_STATUSCODE_GOOD)
- return ret;
- }
- return ret;
- }
- static status NetworkMessage_decodeJsonInternal(UA_NetworkMessage *dst, CtxJson *ctx,
- ParseCtx *parseCtx) {
- memset(dst, 0, sizeof(UA_NetworkMessage));
- dst->chunkMessage = UA_FALSE;
- dst->groupHeaderEnabled = UA_FALSE;
- dst->payloadHeaderEnabled = UA_FALSE;
- dst->picosecondsEnabled = UA_FALSE;
- dst->promotedFieldsEnabled = UA_FALSE;
- /* Look forward for publisheId, if present check if type if primitve (Number) or String. */
- u8 publishIdTypeIndex = UA_TYPES_STRING;
- size_t searchResultPublishIdType = 0;
- status found = lookAheadForKey(UA_DECODEKEY_PUBLISHERID, ctx,
- parseCtx, &searchResultPublishIdType);
- if(found == UA_STATUSCODE_GOOD) {
- jsmntok_t publishIdToken = parseCtx->tokenArray[searchResultPublishIdType];
- if(publishIdToken.type == JSMN_PRIMITIVE) {
- publishIdTypeIndex = UA_TYPES_UINT64;
- dst->publisherIdType = UA_PUBLISHERDATATYPE_UINT64; //store in biggest possible
- } else if(publishIdToken.type == JSMN_STRING) {
- publishIdTypeIndex = UA_TYPES_STRING;
- dst->publisherIdType = UA_PUBLISHERDATATYPE_STRING;
- } else {
- return UA_STATUSCODE_BADDECODINGERROR;
- }
- }
- /* Is Messages an Array? How big? */
- size_t messageCount = 0;
- size_t searchResultMessages = 0;
- found = lookAheadForKey(UA_DECODEKEY_MESSAGES, ctx, parseCtx, &searchResultMessages);
- if(found != UA_STATUSCODE_GOOD)
- return UA_STATUSCODE_BADNOTIMPLEMENTED;
- jsmntok_t bodyToken = parseCtx->tokenArray[searchResultMessages];
- if(bodyToken.type != JSMN_ARRAY)
- return UA_STATUSCODE_BADNOTIMPLEMENTED;
- messageCount = (size_t)parseCtx->tokenArray[searchResultMessages].size;
- /* Set up custom context for the dataSetwriterId */
- size_t currentCustomIndex = 0;
- parseCtx->custom = (void*)UA_calloc(messageCount, sizeof(UA_UInt16));
- parseCtx->currentCustomIndex = ¤tCustomIndex;
- parseCtx->numCustom = messageCount;
- /* MessageType */
- UA_Boolean isUaData = UA_TRUE;
- size_t searchResultMessageType = 0;
- found = lookAheadForKey(UA_DECODEKEY_MESSAGETYPE, ctx, parseCtx, &searchResultMessageType);
- if(found != UA_STATUSCODE_GOOD)
- return UA_STATUSCODE_BADDECODINGERROR;
- size_t size = (size_t)(parseCtx->tokenArray[searchResultMessageType].end - parseCtx->tokenArray[searchResultMessageType].start);
- char* msgType = (char*)(ctx->pos + parseCtx->tokenArray[searchResultMessageType].start);
- if(size == 7) { //ua-data
- if(strncmp(msgType, "ua-data", size) != 0)
- return UA_STATUSCODE_BADDECODINGERROR;
- isUaData = UA_TRUE;
- } else if(size == 11) { //ua-metadata
- if(strncmp(msgType, "ua-metadata", size) != 0)
- return UA_STATUSCODE_BADDECODINGERROR;
- isUaData = UA_FALSE;
- } else {
- return UA_STATUSCODE_BADDECODINGERROR;
- }
- //TODO: MetaData
- if(!isUaData)
- return UA_STATUSCODE_BADNOTIMPLEMENTED;
-
- /* Network Message */
- UA_String messageType;
- DecodeEntry entries[5] = {
- {UA_DECODEKEY_MESSAGEID, &dst->messageId, getDecodeSignature(UA_TYPES_STRING), false, NULL},
- {UA_DECODEKEY_MESSAGETYPE, &messageType, NULL, false, NULL},
- {UA_DECODEKEY_PUBLISHERID, &dst->publisherId.publisherIdString, getDecodeSignature(publishIdTypeIndex), false, NULL},
- {UA_DECODEKEY_DATASETCLASSID, &dst->dataSetClassId, getDecodeSignature(UA_TYPES_GUID), false, NULL},
- {UA_DECODEKEY_MESSAGES, &dst->payload.dataSetPayload.dataSetMessages, &DatasetMessage_Array_decodeJsonInternal, false, NULL}
- };
- //Store publisherId in correct union
- if(publishIdTypeIndex == UA_TYPES_UINT64)
- entries[2].fieldPointer = &dst->publisherId.publisherIdUInt64;
- status ret = decodeFields(ctx, parseCtx, entries, 5, NULL);
- if(ret != UA_STATUSCODE_GOOD)
- return ret;
- dst->messageIdEnabled = entries[0].found;
- dst->publisherIdEnabled = entries[2].found;
- if(dst->publisherIdEnabled)
- dst->publisherIdType = UA_PUBLISHERDATATYPE_STRING;
- dst->dataSetClassIdEnabled = entries[3].found;
- dst->payloadHeaderEnabled = UA_TRUE;
- dst->payloadHeader.dataSetPayloadHeader.count = (UA_Byte)messageCount;
- //Set the dataSetWriterIds. They are filled in the dataSet decoding.
- dst->payloadHeader.dataSetPayloadHeader.dataSetWriterIds = (UA_UInt16*)parseCtx->custom;
- return ret;
- }
- status UA_NetworkMessage_decodeJson(UA_NetworkMessage *dst, const UA_ByteString *src){
- /* Set up the context */
- CtxJson ctx;
- memset(&ctx, 0, sizeof(CtxJson));
- ParseCtx parseCtx;
- memset(&parseCtx, 0, sizeof(ParseCtx));
- parseCtx.tokenArray = (jsmntok_t*)malloc(sizeof(jsmntok_t) * TOKENCOUNT);
- memset(parseCtx.tokenArray, 0, sizeof(jsmntok_t) * TOKENCOUNT);
- status ret = tokenize(&parseCtx, &ctx, src);
- if(ret != UA_STATUSCODE_GOOD){
- return ret;
- }
- ret = NetworkMessage_decodeJsonInternal(dst, &ctx, &parseCtx);
- free(parseCtx.tokenArray);
- return ret;
- }
|