feat(core): Expose binary encoding/decoding functions

This commit is contained in:
Julius Pfrommer 2021-08-14 17:01:40 +02:00 committed by Julius Pfrommer
parent 4d3422524c
commit b164c0e7f4
4 changed files with 88 additions and 40 deletions

View File

@ -1018,6 +1018,14 @@ struct UA_DataType {
UA_DataTypeMember *members;
};
/* Datatype arrays with custom type definitions can be added in a linked list to
* the client or server configuration. */
typedef struct UA_DataTypeArray {
const struct UA_DataTypeArray *next;
const size_t typesSize;
const UA_DataType *types;
} UA_DataTypeArray;
/* Test if the data type is a numeric builtin data type. This includes Boolean,
* integers and floating point numbers. Not included are DateTime and
* StatusCode. */
@ -1091,6 +1099,41 @@ UA_StatusCode UA_EXPORT
UA_print(const void *p, const UA_DataType *type, UA_String *output);
#endif
/**
* Encodeing/Decoding
* ^^^^^^^^^^^^^^^^^^
* Encodeing and decoding routines for the available formats. For all formats
* the _calcSize, _encode and _decode methods are provided. */
/* Returns the number of bytes the value p takes in binary encoding. Returns
* zero if an error occurs. */
UA_EXPORT size_t
UA_calcSizeBinary(const void *p, const UA_DataType *type);
/* Encodes a data-structure in the binary format. If outBuf has a length of
* zero, a buffer of the required size is allocated. Otherwise, encoding into
* the existing outBuf is attempted (and may fail if the buffer is too
* small). */
UA_EXPORT UA_StatusCode
UA_encodeBinary(const void *p, const UA_DataType *type,
UA_ByteString *outBuf);
/* The structure with the decoding options may be extended in the future.
* Zero-out the entire structure initially to ensure code-compatibility when
* more fields are added in a later release. */
typedef struct {
const UA_DataTypeArray *customTypes; /* Begin of a linked list with custom
* datatype definitions */
} UA_DecodeBinaryOptions;
/* Decodes a data structure from the input buffer in the binary format. It is
* assumed that `p` points to valid memory (not necessarily zeroed out). The
* options can be NULL and will be disregarded in that case. */
UA_EXPORT UA_StatusCode
UA_decodeBinary(const UA_ByteString *inBuf,
void *p, const UA_DataType *type,
const UA_DecodeBinaryOptions *options);
/**
* .. _array-handling:
*
@ -1202,14 +1245,6 @@ UA_Guid UA_EXPORT UA_Guid_random(void); /* no cryptographic entropy */
# define UA_TYPENAME(name)
#endif
/* Datatype arrays with custom type definitions can be added in a linked list to
* the client or server configuration. */
typedef struct UA_DataTypeArray {
const struct UA_DataTypeArray *next;
const size_t typesSize;
const UA_DataType *types;
} UA_DataTypeArray;
/**
* .. include:: types_generated.rst */

View File

@ -1492,6 +1492,34 @@ UA_encodeBinaryInternal(const void *src, const UA_DataType *type,
return ret;
}
UA_StatusCode
UA_encodeBinary(const void *p, const UA_DataType *type,
UA_ByteString *outBuf) {
/* Allocate buffer */
UA_Boolean allocated = false;
status res = UA_STATUSCODE_GOOD;
if(outBuf->length == 0) {
size_t len = UA_calcSizeBinary(p, type);
res = UA_ByteString_allocBuffer(outBuf, len);
if(res != UA_STATUSCODE_GOOD)
return res;
allocated = true;
}
/* Encode */
u8 *pos = outBuf->data;
const u8 *posEnd = &outBuf->data[outBuf->length];
res = UA_encodeBinaryInternal(p, type, &pos, &posEnd, NULL, NULL);
/* Clean up */
if(res == UA_STATUSCODE_GOOD) {
outBuf->length = (size_t)((uintptr_t)pos - (uintptr_t)outBuf->data);
} else if(allocated) {
UA_ByteString_clear(outBuf);
}
return res;
}
static status
decodeBinaryNotImplemented(void *dst, const UA_DataType *type, Ctx *ctx) {
(void)dst, (void)type, (void)ctx;
@ -1683,6 +1711,15 @@ UA_decodeBinaryInternal(const UA_ByteString *src, size_t *offset,
return ret;
}
UA_StatusCode
UA_decodeBinary(const UA_ByteString *inBuf,
void *p, const UA_DataType *type,
const UA_DecodeBinaryOptions *options) {
size_t offset = 0;
const UA_DataTypeArray *customTypes = options ? options->customTypes : NULL;
return UA_decodeBinaryInternal(inBuf, &offset, p, type, customTypes);
}
/**
* Compute the Message Size
* ------------------------

View File

@ -67,11 +67,6 @@ UA_decodeBinaryInternal(const UA_ByteString *src, size_t *offset,
const UA_DataTypeArray *customTypes)
UA_FUNC_ATTR_WARN_UNUSED_RESULT;
/* Returns the number of bytes the value p takes in binary encoding. Returns
* zero if an error occurs. */
size_t
UA_calcSizeBinary(const void *p, const UA_DataType *type);
const UA_DataType *
UA_findDataTypeByBinary(const UA_NodeId *typeId);

View File

@ -19,15 +19,12 @@
#endif
#include <open62541/types.h>
#include <stdio.h>
/* Internal headers */
#include <open62541/types_generated.h>
#include <open62541/types_generated_handling.h>
/* Internal headers */
#include "ua_pubsub_networkmessage.h"
#include "ua_types_encoding_binary.h"
#include "ua_types_encoding_json.h"
static UA_StatusCode
@ -37,17 +34,11 @@ encode(const UA_ByteString *buf, UA_ByteString *out,
if(!data)
return UA_STATUSCODE_BADOUTOFMEMORY;
size_t offset = 0;
UA_StatusCode retval = UA_decodeBinary(buf, &offset, data, type, NULL);
UA_StatusCode retval = UA_decodeBinary(buf, data, type, NULL);
if(retval != UA_STATUSCODE_GOOD) {
free(data);
return retval;
}
if(offset != buf->length) {
UA_delete(data, type);
fprintf(stderr, "Input buffer not completely read\n");
return UA_STATUSCODE_BADINTERNALERROR;
}
size_t jsonLength = UA_calcSizeJson(data, type, NULL, 0, NULL, 0, true);
retval = UA_ByteString_allocBuffer(out, jsonLength);
@ -72,34 +63,24 @@ encode(const UA_ByteString *buf, UA_ByteString *out,
static UA_StatusCode
decode(const UA_ByteString *buf, UA_ByteString *out,
const UA_DataType *type) {
/* Allocate memory for the type */
void *data = malloc(type->memSize);
if(!data)
return UA_STATUSCODE_BADOUTOFMEMORY;
/* Decode JSON */
UA_StatusCode retval = UA_decodeJson(buf, data, type);
if(retval != UA_STATUSCODE_GOOD) {
free(data);
return retval;
}
size_t binLength = UA_calcSizeBinary(data, type);
retval = UA_ByteString_allocBuffer(out, binLength);
if(retval != UA_STATUSCODE_GOOD) {
UA_delete(data, type);
return retval;
}
/* Encode Binary. Internally allocates the buffer upon success */
retval = UA_encodeBinary(data, type, out);
uint8_t *bufPos = &out->data[0];
const uint8_t *bufEnd = &out->data[out->length];
retval = UA_encodeBinary(data, type, &bufPos, &bufEnd, NULL, NULL);
/* Clean up */
UA_delete(data, type);
if(retval != UA_STATUSCODE_GOOD) {
UA_ByteString_clear(out);
return retval;
}
out->length = (size_t)((uintptr_t)bufPos - (uintptr_t)out->data);
return UA_STATUSCODE_GOOD;
return retval;
}
#ifdef UA_ENABLE_PUBSUB