Przeglądaj źródła

add handling of custom types to the decoding function, client and server

Julius Pfrommer 8 lat temu
rodzic
commit
e9766c7663

+ 1 - 1
examples/server_readspeed.c

@@ -70,7 +70,7 @@ int main(int argc, char** argv) {
 
     for(int i = 0; i < 1000000; i++) {
         offset = 0;
-        retval |= UA_decodeBinary(&request_msg, &offset, &rq, &UA_TYPES[UA_TYPES_READREQUEST]);
+        retval |= UA_decodeBinary(&request_msg, &offset, &rq, &UA_TYPES[UA_TYPES_READREQUEST], 0, NULL);
 
         UA_ReadResponse_init(&rr);
         Service_Read(server, &adminSession, &rq, &rr);

+ 4 - 0
include/ua_client.h

@@ -55,6 +55,10 @@ typedef struct UA_ClientConfig {
     UA_Logger logger;
     UA_ConnectionConfig localConnectionConfig;
     UA_ConnectClientConnection connectionFunc;
+
+    /* Custom DataTypes */
+    size_t customDataTypesSize;
+    const UA_DataType *customDataTypes;
 } UA_ClientConfig;
 
 /**

+ 31 - 10
include/ua_server.h

@@ -98,29 +98,46 @@ typedef struct {
     void (*closeSession)(const UA_NodeId *sessionId, void *sessionHandle);
 
     /* Access control for all nodes*/
-    UA_UInt32 (*getUserRightsMask)(const UA_NodeId *sessionId, void *sessionHandle, const UA_NodeId *nodeId);
+    UA_UInt32 (*getUserRightsMask)(const UA_NodeId *sessionId,
+                                   void *sessionHandle,
+                                   const UA_NodeId *nodeId);
 
     /* Additional access control for variable nodes */
-    UA_Byte (*getUserAccessLevel)(const UA_NodeId *sessionId, void *sessionHandle, const UA_NodeId *nodeId);
+    UA_Byte (*getUserAccessLevel)(const UA_NodeId *sessionId,
+                                  void *sessionHandle,
+                                  const UA_NodeId *nodeId);
 
     /* Additional access control for method nodes */
-    UA_Boolean (*getUserExecutable)(const UA_NodeId *sessionId, void *sessionHandle, const UA_NodeId *methodId);
+    UA_Boolean (*getUserExecutable)(const UA_NodeId *sessionId,
+                                    void *sessionHandle,
+                                    const UA_NodeId *methodId);
 
-    /* Additional access control for calling a method node in the context of a specific object */
-    UA_Boolean (*getUserExecutableOnObject)(const UA_NodeId *sessionId, void *sessionHandle,
-                                            const UA_NodeId *methodId, const UA_NodeId *objectId);
+    /* Additional access control for calling a method node in the context of a
+     * specific object */
+    UA_Boolean (*getUserExecutableOnObject)(const UA_NodeId *sessionId,
+                                            void *sessionHandle,
+                                            const UA_NodeId *methodId,
+                                            const UA_NodeId *objectId);
 
     /* Allow adding a node */
-    UA_Boolean (*allowAddNode)(const UA_NodeId *sessionId, void *sessionHandle, const UA_AddNodesItem *item);
+    UA_Boolean (*allowAddNode)(const UA_NodeId *sessionId,
+                               void *sessionHandle,
+                               const UA_AddNodesItem *item);
 
     /* Allow adding a reference */
-    UA_Boolean (*allowAddReference)(const UA_NodeId *sessionId, void *sessionHandle, const UA_AddReferencesItem *item);
+    UA_Boolean (*allowAddReference)(const UA_NodeId *sessionId,
+                                    void *sessionHandle,
+                                    const UA_AddReferencesItem *item);
 
     /* Allow deleting a node */
-    UA_Boolean (*allowDeleteNode)(const UA_NodeId *sessionId, void *sessionHandle, const UA_DeleteNodesItem *item);
+    UA_Boolean (*allowDeleteNode)(const UA_NodeId *sessionId,
+                                  void *sessionHandle,
+                                  const UA_DeleteNodesItem *item);
 
     /* Allow deleting a reference */
-    UA_Boolean (*allowDeleteReference)(const UA_NodeId *sessionId, void *sessionHandle, const UA_DeleteReferencesItem *item);
+    UA_Boolean (*allowDeleteReference)(const UA_NodeId *sessionId,
+                                       void *sessionHandle,
+                                       const UA_DeleteReferencesItem *item);
 } UA_AccessControl;
 
 /**
@@ -151,6 +168,10 @@ typedef struct {
     UA_ApplicationDescription applicationDescription;
     UA_ByteString serverCertificate;
 
+    /* Custom DataTypes */
+    size_t customDataTypesSize;
+    const UA_DataType *customDataTypes;
+
     /* Networking */
     size_t networkLayersSize;
     UA_ServerNetworkLayer *networkLayers;

+ 2 - 2
include/ua_types.h

@@ -763,8 +763,8 @@ struct UA_DataType {
     UA_Byte    membersSize;      /* How many members does the type have? */
     UA_Boolean builtin      : 1; /* The type is "builtin" and has dedicated de-
                                     and encoding functions */
-    UA_Boolean fixedSize    : 1; /* The type (and its members) contains no
-                                    pointers */
+    UA_Boolean pointerFree  : 1; /* The type (and its members) contains no
+                                    pointers that need to be freed */
     UA_Boolean overlayable  : 1; /* The type has the identical memory layout in
                                     memory and on the binary stream. */
     UA_UInt16  binaryEncodingId; /* NodeId of datatype when encoded as binary */

+ 9 - 1
plugins/ua_config_standard.c

@@ -72,6 +72,10 @@ const UA_EXPORT UA_ServerConfig UA_ServerConfig_standard = {
         .discoveryUrls = NULL },
     .serverCertificate = UA_STRING_STATIC_NULL,
 
+    /* Custom DataTypes */
+    .customDataTypesSize = 0,
+    .customDataTypes = NULL,
+
     /* Networking */
     .networkLayersSize = 0,
     .networkLayers = NULL,
@@ -131,7 +135,11 @@ const UA_EXPORT UA_ClientConfig UA_ClientConfig_standard = {
         .maxMessageSize = 0, /* 0 -> unlimited */
         .maxChunkCount = 0 /* 0 -> unlimited */
     },
-    .connectionFunc = UA_ClientConnectionTCP
+    .connectionFunc = UA_ClientConnectionTCP,
+
+    /* Custom DataTypes */
+    .customDataTypesSize = 0,
+    .customDataTypes = NULL
 };
 
 /****************************************/

+ 4 - 2
src/client/ua_client.c

@@ -762,7 +762,7 @@ processServiceResponse(struct ResponseDescription *rd, UA_SecureChannel *channel
         if(UA_NodeId_equal(&responseId, &serviceFaultNodeId)) {
             /* Take the statuscode from the servicefault */
             retval = UA_decodeBinary(message, &offset, rd->response,
-                                     &UA_TYPES[UA_TYPES_SERVICEFAULT]);
+                                     &UA_TYPES[UA_TYPES_SERVICEFAULT], 0, NULL);
         } else {
             UA_LOG_ERROR(rd->client->config.logger, UA_LOGCATEGORY_CLIENT,
                          "Reply answers the wrong request. Expected ns=%i,i=%i."
@@ -776,7 +776,9 @@ processServiceResponse(struct ResponseDescription *rd, UA_SecureChannel *channel
     }
 
     /* Decode the response */
-    retval = UA_decodeBinary(message, &offset, rd->response, rd->responseType);
+    retval = UA_decodeBinary(message, &offset, rd->response, rd->responseType,
+                             rd->client->config.customDataTypesSize,
+                             rd->client->config.customDataTypes);
 
  finish:
     if(retval == UA_STATUSCODE_GOOD) {

+ 3 - 1
src/server/ua_server_binary.c

@@ -392,7 +392,9 @@ processMSG(UA_Server *server, UA_SecureChannel *channel,
     /* Decode the request */
     void *request = UA_alloca(requestType->memSize);
     UA_RequestHeader *requestHeader = (UA_RequestHeader*)request;
-    retval = UA_decodeBinary(msg, offset, request, requestType);
+    retval = UA_decodeBinary(msg, offset, request, requestType,
+                             server->config.customDataTypesSize,
+                             server->config.customDataTypes);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_LOG_DEBUG_CHANNEL(server->config.logger, channel, "Could not decode the request");
         sendError(channel, msg, requestPos, responseType, requestId, retval);

+ 5 - 5
src/ua_types.c

@@ -590,7 +590,7 @@ UA_Variant_copyRange(const UA_Variant *orig_src, UA_Variant *dst,
     uintptr_t nextsrc = (uintptr_t)src->data + (elem_size * first);
     if(nextrange.dimensionsSize == 0) {
         /* no nextrange */
-        if(src->type->fixedSize) {
+        if(src->type->pointerFree) {
             for(size_t i = 0; i < block_count; ++i) {
                 memcpy((void*)nextdst, (void*)nextsrc, elem_size * block);
                 nextdst += block * elem_size;
@@ -683,7 +683,7 @@ Variant_setRange(UA_Variant *v, void *array, size_t arraySize,
     size_t elem_size = v->type->memSize;
     uintptr_t nextdst = (uintptr_t)v->data + (first * elem_size);
     uintptr_t nextsrc = (uintptr_t)array;
-    if(v->type->fixedSize || !copy) {
+    if(v->type->pointerFree || !copy) {
         for(size_t i = 0; i < block_count; ++i) {
             memcpy((void*)nextdst, (void*)nextsrc, elem_size * block);
             nextsrc += block * elem_size;
@@ -702,7 +702,7 @@ Variant_setRange(UA_Variant *v, void *array, size_t arraySize,
     }
 
     /* If members were moved, initialize original array to prevent reuse */
-    if(!copy && !v->type->fixedSize)
+    if(!copy && !v->type->pointerFree)
         memset(array, 0, sizeof(elem_size)*arraySize);
 
     return retval;
@@ -1002,7 +1002,7 @@ UA_Array_copy(const void *src, size_t src_size,
     if(!*dst)
         return UA_STATUSCODE_BADOUTOFMEMORY;
 
-    if(type->fixedSize) {
+    if(type->pointerFree) {
         memcpy(*dst, src, type->memSize * src_size);
         return UA_STATUSCODE_GOOD;
     }
@@ -1024,7 +1024,7 @@ UA_Array_copy(const void *src, size_t src_size,
 
 void
 UA_Array_delete(void *p, size_t size, const UA_DataType *type) {
-    if(!type->fixedSize) {
+    if(!type->pointerFree) {
         uintptr_t ptr = (uintptr_t)p;
         for(size_t i = 0; i < size; ++i) {
             UA_deleteMembers((void*)ptr, type);

+ 25 - 9
src/ua_types_encoding_binary.c

@@ -48,8 +48,13 @@ extern const UA_decodeBinarySignature decodeBinaryJumpTable[UA_BUILTIN_TYPES_COU
 typedef size_t (*UA_calcSizeBinarySignature)(const void *UA_RESTRICT p, const UA_DataType *contenttype);
 extern const UA_calcSizeBinarySignature calcSizeBinaryJumpTable[UA_BUILTIN_TYPES_COUNT + 1];
 
+/* Pointer to custom datatypes in the server or client. Set inside
+ * UA_decodeBinary */
+UA_THREAD_LOCAL size_t customTypesSize;
+UA_THREAD_LOCAL const UA_DataType *customTypes;
+
 /* We give pointers to the current position and the last position in the buffer
-   instead of a string with an offset. */
+ * instead of a string with an offset. */
 UA_THREAD_LOCAL UA_Byte * pos;
 UA_THREAD_LOCAL UA_Byte * end;
 
@@ -766,9 +771,15 @@ LocalizedText_decodeBinary(UA_LocalizedText *dst, const UA_DataType *_) {
 
 static UA_StatusCode
 findDataTypeByBinary(const UA_NodeId *typeId, const UA_DataType **findtype) {
-    for(size_t i = 0; i < UA_TYPES_COUNT; ++i) {
-        if (UA_TYPES[i].binaryEncodingId == typeId->identifier.numeric) {
-            *findtype = &UA_TYPES[i];
+    const UA_DataType *types = UA_TYPES;
+    size_t typesSize = UA_TYPES_COUNT;
+    if(typeId->namespaceIndex != 0) {
+        types = customTypes;
+        typesSize = customTypesSize;
+    }
+    for(size_t i = 0; i < typesSize; ++i) {
+        if(types[i].binaryEncodingId == typeId->identifier.numeric) {
+            *findtype = &types[i];
             return UA_STATUSCODE_GOOD;
         }
     }
@@ -825,7 +836,7 @@ ExtensionObject_decodeBinary(UA_ExtensionObject *dst, const UA_DataType *_) {
     UA_NodeId_init(&typeId);
     UA_StatusCode retval = NodeId_decodeBinary(&typeId, NULL);
     retval |= Byte_decodeBinary(&encoding, NULL);
-    if(typeId.namespaceIndex != 0 || typeId.identifierType != UA_NODEIDTYPE_NUMERIC)
+    if(typeId.identifierType != UA_NODEIDTYPE_NUMERIC)
         retval = UA_STATUSCODE_BADDECODINGERROR;
     if(retval != UA_STATUSCODE_GOOD) {
         UA_NodeId_deleteMembers(&typeId);
@@ -992,7 +1003,7 @@ Variant_decodeBinary(UA_Variant *dst, const UA_DataType *_) {
 
         /* search for the datatype. use extensionobject if nothing is found */
         dst->type = &UA_TYPES[UA_TYPES_EXTENSIONOBJECT];
-        if(typeId.namespaceIndex == 0 && typeId.identifierType == UA_NODEIDTYPE_NUMERIC &&
+        if(typeId.identifierType == UA_NODEIDTYPE_NUMERIC &&
            eo_encoding == UA_EXTENSIONOBJECT_ENCODED_BYTESTRING) {
             UA_assert(typeId.identifier.byteString.data == NULL); /* for clang analyzer <= 3.7 */
             if(findDataTypeByBinary(&typeId, &dst->type) == UA_STATUSCODE_GOOD)
@@ -1302,13 +1313,18 @@ UA_decodeBinaryInternal(void *dst, const UA_DataType *type) {
 }
 
 UA_StatusCode
-UA_decodeBinary(const UA_ByteString *src, size_t *offset,
-                void *dst, const UA_DataType *type) {
+UA_decodeBinary(const UA_ByteString *src, size_t *offset, void *dst,
+                const UA_DataType *type, size_t cTS, const UA_DataType *cT) {
     /* Initialize the destination */
     memset(dst, 0, type->memSize);
 
+    /* Store the pointers to the custom datatypes. They might be needed during
+     * decoding of variants. */
+    customTypesSize = cTS;
+    customTypes = cT;
+
     /* Set the (thread-local) position and end pointers to save function
-       arguments */
+     * arguments */
     pos = &src->data[*offset];
     end = &src->data[src->length];
 

+ 2 - 1
src/ua_types_encoding_binary.h

@@ -12,7 +12,8 @@ UA_encodeBinary(const void *src, const UA_DataType *type,
 
 UA_StatusCode UA_EXPORT
 UA_decodeBinary(const UA_ByteString *src, size_t *offset, void *dst,
-                const UA_DataType *type) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+                const UA_DataType *type, size_t customTypesSize,
+                const UA_DataType *customTypes) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
 
 size_t UA_calcSizeBinary(void *p, const UA_DataType *type);
 

+ 4 - 0
tests/CMakeLists.txt

@@ -53,6 +53,10 @@ add_executable(check_types_range check_types_range.c $<TARGET_OBJECTS:open62541-
 target_link_libraries(check_types_range ${LIBS})
 add_test_valgrind(types_range ${CMAKE_CURRENT_BINARY_DIR}/check_types_range)
 
+add_executable(check_types_custom check_types_custom.c $<TARGET_OBJECTS:open62541-object>)
+target_link_libraries(check_types_custom ${LIBS})
+add_test_valgrind(types_custom ${CMAKE_CURRENT_BINARY_DIR}/check_types_custom)
+
 add_executable(check_chunking check_chunking.c $<TARGET_OBJECTS:open62541-object>)
 target_link_libraries(check_chunking ${LIBS})
 add_test_valgrind(chunking ${CMAKE_CURRENT_BINARY_DIR}/check_chunking)

+ 154 - 0
tests/check_types_custom.c

@@ -0,0 +1,154 @@
+#include "ua_types.h"
+#include "ua_types_generated_handling.h"
+#include "ua_types_encoding_binary.h"
+#include "ua_util.h"
+#include "check.h"
+
+/* The custom datatype for describing a 3d position */
+
+typedef struct {
+    UA_Float x;
+    UA_Float y;
+    UA_Float z;
+} Point;
+
+/* The datatype description for the Point datatype */
+
+#define padding_y offsetof(Point,y) - offsetof(Point,x) - sizeof(UA_Float)
+#define padding_z offsetof(Point,z) - offsetof(Point,y) - sizeof(UA_Float)
+
+static UA_DataTypeMember members[3] = {
+    /* x */
+    {
+#ifdef UA_ENABLE_TYPENAMES
+        "x",            /* .memberName */
+#endif
+        UA_TYPES_FLOAT, /* .memberTypeIndex, points into UA_TYPES since
+                           .namespaceZero is true */
+        0,              /* .padding */
+        true,           /* .namespaceZero, see .memberTypeIndex */
+        false           /* .isArray */
+    },
+
+    /* y */
+    {
+#ifdef UA_ENABLE_TYPENAMES
+        "y",
+#endif
+        UA_TYPES_FLOAT, padding_y, true, false
+    },
+
+    /* z */
+    {
+#ifdef UA_ENABLE_TYPENAMES
+        "y",
+#endif
+        UA_TYPES_FLOAT, padding_z, true, false
+    }
+};
+
+static const UA_DataType PointType = {
+#ifdef UA_ENABLE_TYPENAMES
+    "Point",                         /* .typeName */
+#endif
+    {1, UA_NODEIDTYPE_NUMERIC, {1}}, /* .typeId */
+    sizeof(Point),                   /* .memSize */
+    0,                               /* .typeIndex, in the array of custom types */
+    3,                               /* .membersSize */
+    false,                           /* .builtin */
+    true,                            /* .pointerFree */
+    false,                           /* .overlayable (depends on endianness and
+                                         the absence of padding) */
+    0,                               /* .binaryEncodingId, the numeric
+                                         identifier used on the wire (the
+                                         namespaceindex is from .typeId) */
+    members
+};
+
+START_TEST(parseCustomScalar) {
+    Point p;
+    p.x = 1.0;
+    p.y = 2.0;
+    p.z = 3.0;
+    
+    UA_Variant var;
+    UA_Variant_init(&var);
+    UA_Variant_setScalar(&var, &p, &PointType);
+
+    size_t buflen = UA_calcSizeBinary(&var, &UA_TYPES[UA_TYPES_VARIANT]);
+    UA_ByteString buf;
+    UA_StatusCode retval = UA_ByteString_allocBuffer(&buf, buflen);
+    ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
+
+    size_t offset = 0;
+    retval = UA_encodeBinary(&var, &UA_TYPES[UA_TYPES_VARIANT], NULL, NULL,
+                             &buf, &offset);
+    ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
+
+    UA_Variant var2;
+    offset = 0;
+    retval = UA_decodeBinary(&buf, &offset, &var2, &UA_TYPES[UA_TYPES_VARIANT], 1, &PointType);
+    ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
+    ck_assert_ptr_eq(var2.type, &PointType);
+
+    Point *p2 = (Point*)var2.data;
+    ck_assert(p.x == p2->x);
+        
+    UA_Variant_deleteMembers(&var2);
+    UA_ByteString_deleteMembers(&buf);
+} END_TEST
+
+START_TEST(parseCustomArray) {
+    Point ps[10];
+    for(size_t i = 0; i < 10; ++i) {
+        ps[i].x = (UA_Float)(1*i);
+        ps[i].y = (UA_Float)(2*i);
+        ps[i].z = (UA_Float)(3*i);
+    }
+
+    UA_Variant var;
+    UA_Variant_init(&var);
+    UA_Variant_setArray(&var, (void*)ps, 10, &PointType);
+
+    size_t buflen = UA_calcSizeBinary(&var, &UA_TYPES[UA_TYPES_VARIANT]);
+    UA_ByteString buf;
+    UA_StatusCode retval = UA_ByteString_allocBuffer(&buf, buflen);
+    ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
+
+    size_t offset = 0;
+    retval = UA_encodeBinary(&var, &UA_TYPES[UA_TYPES_VARIANT], NULL, NULL,
+                             &buf, &offset);
+    ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
+
+    UA_Variant var2;
+    offset = 0;
+    retval = UA_decodeBinary(&buf, &offset, &var2, &UA_TYPES[UA_TYPES_VARIANT], 1, &PointType);
+    ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
+    ck_assert_ptr_eq(var2.type, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]);
+    ck_assert_int_eq(var2.arrayLength, 10);
+
+    UA_ExtensionObject *eo = (UA_ExtensionObject*)var2.data;
+    ck_assert_int_eq(eo->encoding, UA_EXTENSIONOBJECT_DECODED);
+    ck_assert_ptr_eq(eo->content.decoded.type, &PointType);
+    Point *p2 = (Point*)eo->content.decoded.data;
+    ck_assert(p2->x == 0.0);
+        
+    UA_Variant_deleteMembers(&var2);
+    UA_ByteString_deleteMembers(&buf);
+} END_TEST
+
+int main(void) {
+    Suite *s  = suite_create("Test Custom DataType Encoding");
+    TCase *tc = tcase_create("test cases");
+    tcase_add_test(tc, parseCustomScalar);
+    tcase_add_test(tc, parseCustomArray);
+    suite_add_tcase(s, tc);
+
+    SRunner *sr = srunner_create(s);
+    srunner_set_fork_status(sr, CK_NOFORK);
+    srunner_run_all (sr, CK_NORMAL);
+    int number_failed = srunner_ntests_failed(sr);
+    srunner_free(sr);
+
+    return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}

+ 4 - 4
tests/check_types_memory.c

@@ -72,7 +72,7 @@ START_TEST(encodeShallYieldDecode) {
 
     // when
     void *obj2 = UA_new(&UA_TYPES[_i]);
-    pos = 0; retval = UA_decodeBinary(&msg1, &pos, obj2, &UA_TYPES[_i]);
+    pos = 0; retval = UA_decodeBinary(&msg1, &pos, obj2, &UA_TYPES[_i], 0, NULL); 
     ck_assert_msg(retval == UA_STATUSCODE_GOOD, "could not decode idx=%d,nodeid=%i",
                   _i, UA_TYPES[_i].typeId.identifier.numeric);
     ck_assert(!memcmp(obj1, obj2, UA_TYPES[_i].memSize)); // bit identical decoding
@@ -110,7 +110,7 @@ START_TEST(decodeShallFailWithTruncatedBufferButSurvive) {
     void *obj2 = UA_new(&UA_TYPES[_i]);
     msg1.length = pos / 2;
     pos = 0;
-    retval = UA_decodeBinary(&msg1, &pos, obj2, &UA_TYPES[_i]);
+    retval = UA_decodeBinary(&msg1, &pos, obj2, &UA_TYPES[_i], 0, NULL); 
     ck_assert_int_ne(retval, UA_STATUSCODE_GOOD);
     UA_delete(obj2, &UA_TYPES[_i]);
     UA_ByteString_deleteMembers(&msg1);
@@ -143,7 +143,7 @@ START_TEST(decodeScalarBasicTypeFromRandomBufferShallSucceed) {
         }
         size_t pos = 0;
         obj1 = UA_new(&UA_TYPES[_i]);
-        retval |= UA_decodeBinary(&msg1, &pos, obj1, &UA_TYPES[_i]);
+        retval |= UA_decodeBinary(&msg1, &pos, obj1, &UA_TYPES[_i], 0, NULL);
         //then
         ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Decoding %d from random buffer", UA_TYPES[_i].typeId.identifier.numeric);
         // finally
@@ -177,7 +177,7 @@ START_TEST(decodeComplexTypeFromRandomBufferShallSurvive) {
         }
         size_t pos = 0;
         void *obj1 = UA_new(&UA_TYPES[_i]);
-        retval |= UA_decodeBinary(&msg1, &pos, obj1, &UA_TYPES[_i]);
+        retval |= UA_decodeBinary(&msg1, &pos, obj1, &UA_TYPES[_i], 0, NULL);
         UA_delete(obj1, &UA_TYPES[_i]);
     }
 

+ 14 - 14
tools/generate_datatypes.py

@@ -27,9 +27,9 @@ builtin_types = ["Boolean", "SByte", "Byte", "Int16", "UInt16", "Int32", "UInt32
 
 # If the type does not contain pointers, it can be copied with memcpy
 # (internally, not into the protocol message). This dict contains the sizes of
-# fixed-size types. Parsed types are added if they apply.
-builtin_fixed_size = ["Boolean", "SByte", "Byte", "Int16", "UInt16", "Int32", "UInt32",
-                      "Int64", "UInt64", "Float", "Double", "DateTime", "Guid", "StatusCode"]
+# pointer-free types. Parsed types are added if they apply.
+builtin_pointerfree = ["Boolean", "SByte", "Byte", "Int16", "UInt16", "Int32", "UInt32",
+                       "Int64", "UInt64", "Float", "Double", "DateTime", "Guid", "StatusCode"]
 
 # Some types can be memcpy'd off the binary stream. That's especially important
 # for arrays. But we need to check if they contain padding and whether the
@@ -62,7 +62,7 @@ class Type(object):
         self.typeIndex = outname.upper() + "_" + self.name.upper()
         self.outname = outname
         self.description = ""
-        self.fixed_size = "false"
+        self.pointerfree = "false"
         self.overlayable = "false"
         if self.name in builtin_types:
             self.builtin = "true"
@@ -89,7 +89,7 @@ class Type(object):
             ",\n#ifdef UA_ENABLE_TYPENAMES\n  .typeName = \"%s\",\n#endif\n" % self.name + \
             "  .memSize = sizeof(UA_" + self.name + ")" + \
             ",\n  .builtin = " + self.builtin + \
-            ",\n  .fixedSize = " + self.fixed_size + \
+            ",\n  .pointerFree = " + self.pointerfree + \
             ",\n  .overlayable = " + self.overlayable + \
             ",\n  .binaryEncodingId = " + binaryEncodingId + \
             ",\n  .membersSize = " + str(len(self.members)) + \
@@ -129,7 +129,7 @@ class Type(object):
     def functions_c(self):
         funcs = "static UA_INLINE void\nUA_%s_init(UA_%s *p) {\n    memset(p, 0, sizeof(UA_%s));\n}\n\n" % (self.name, self.name, self.name)
         funcs += "static UA_INLINE UA_%s *\nUA_%s_new(void) {\n    return (UA_%s*)UA_new(%s);\n}\n\n" % (self.name, self.name, self.name, self.datatype_ptr())
-        if self.fixed_size == "true":
+        if self.pointerfree == "true":
             funcs += "static UA_INLINE UA_StatusCode\nUA_%s_copy(const UA_%s *src, UA_%s *dst) {\n    *dst = *src;\n    return UA_STATUSCODE_GOOD;\n}\n\n" % (self.name, self.name, self.name)
             funcs += "static UA_INLINE void\nUA_%s_deleteMembers(UA_%s *p) { }\n\n" % (self.name, self.name)
         else:
@@ -140,7 +140,7 @@ class Type(object):
 
     def encoding_h(self):
         enc = "static UA_INLINE UA_StatusCode\nUA_%s_encodeBinary(const UA_%s *src, UA_ByteString *dst, size_t *offset) {\n    return UA_encodeBinary(src, %s, NULL, NULL, dst, offset);\n}\n"
-        enc += "static UA_INLINE UA_StatusCode\nUA_%s_decodeBinary(const UA_ByteString *src, size_t *offset, UA_%s *dst) {\n    return UA_decodeBinary(src, offset, dst, %s);\n}"
+        enc += "static UA_INLINE UA_StatusCode\nUA_%s_decodeBinary(const UA_ByteString *src, size_t *offset, UA_%s *dst) {\n    return UA_decodeBinary(src, offset, dst, %s, 0, NULL);\n}"
         return enc % tuple(list(itertools.chain(*itertools.repeat([self.name, self.name, self.datatype_ptr()], 2))))
 
 class BuiltinType(Type):
@@ -150,9 +150,9 @@ class BuiltinType(Type):
         self.typeIndex = "UA_TYPES_" + self.name.upper()
         self.outname = "ua_types"
         self.description = ""
-        self.fixed_size = "false"
-        if self.name in builtin_fixed_size:
-            self.fixed_size = "true"
+        self.pointerfree = "false"
+        if self.name in builtin_pointerfree:
+            self.pointerfree = "true"
         self.overlayable = "false"
         if name in builtin_overlayable:
             self.overlayable = builtin_overlayable[name]
@@ -167,7 +167,7 @@ class BuiltinType(Type):
 class EnumerationType(Type):
     def __init__(self, outname, xml):
         Type.__init__(self, outname, xml)
-        self.fixed_size = "true"
+        self.pointerfree = "true"
         self.overlayable = "UA_BINARY_OVERLAYABLE_INTEGER"
         self.members = [StructMember("", types["Int32"], False)] # encoded as uint32
         self.builtin = "true"
@@ -213,12 +213,12 @@ class StructType(Type):
             isArray = True if child.get("LengthField") else False
             self.members.append(StructMember(memberName, memberType, isArray))
 
-        self.fixed_size = "true"
+        self.pointerfree = "true"
         self.overlayable = "true"
         before = None
         for m in self.members:
-            if m.isArray or m.memberType.fixed_size != "true":
-                self.fixed_size = "false"
+            if m.isArray or m.memberType.pointerfree != "true":
+                self.pointerfree = "false"
                 self.overlayable = "false"
             else:
                 self.overlayable += " && " + m.memberType.overlayable