Browse Source

remove offset for encoding

Julius Pfrommer 7 years ago
parent
commit
d1c49761a4

+ 10 - 8
examples/server_readspeed.c

@@ -51,31 +51,33 @@ int main(int argc, char** argv) {
     retval |= UA_ByteString_allocBuffer(&request_msg, 1000);
     UA_ByteString response_msg;
     retval |= UA_ByteString_allocBuffer(&response_msg, 1000);
-    size_t offset = 0;
-    retval |= UA_encodeBinary(&request, &UA_TYPES[UA_TYPES_READREQUEST], NULL, NULL, &request_msg, &offset);
 
-    clock_t begin, end;
+    UA_Byte *pos = request_msg.data;
+    const UA_Byte *end = &request_msg.data[request_msg.length];
+    retval |= UA_encodeBinary(&request, &UA_TYPES[UA_TYPES_READREQUEST], &pos, &end, NULL, NULL);
+
+    clock_t begin, finish;
     begin = clock();
 
     UA_ReadRequest rq;
     UA_ReadResponse rr;
 
     for(int i = 0; i < 1000000; i++) {
-        offset = 0;
+        size_t offset = 0;
         retval |= UA_decodeBinary(&request_msg, &offset, &rq, &UA_TYPES[UA_TYPES_READREQUEST], 0, NULL);
 
         UA_ReadResponse_init(&rr);
         Service_Read(server, &adminSession, &rq, &rr);
 
-        offset = 0;
-        retval |= UA_encodeBinary(&rr, &UA_TYPES[UA_TYPES_READRESPONSE], NULL, NULL, &response_msg, &offset);
+        pos = request_msg.data;
+        retval |= UA_encodeBinary(&rr, &UA_TYPES[UA_TYPES_READRESPONSE], &pos, &end, NULL, NULL);
 
         UA_ReadRequest_deleteMembers(&rq);
         UA_ReadResponse_deleteMembers(&rr);
     }
 
-    end = clock();
-    double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
+    finish = clock();
+    double time_spent = (double)(finish - begin) / CLOCKS_PER_SEC;
     printf("duration was %f s\n", time_spent);
     printf("retval is %i\n", retval);
 

+ 32 - 24
src/client/ua_client.c

@@ -95,16 +95,17 @@ HelAckHandshake(UA_Client *client) {
     hello.receiveBufferSize = conn->localConf.recvBufferSize;
     hello.sendBufferSize = conn->localConf.sendBufferSize;
 
-    size_t offset = 8;
-    retval = UA_TcpHelloMessage_encodeBinary(&hello, &message, &offset);
+    UA_Byte *bufPos = &message.data[8]; /* skip the header */
+    const UA_Byte *bufEnd = &message.data[message.length];
+    retval = UA_TcpHelloMessage_encodeBinary(&hello, &bufPos, &bufEnd);
     UA_TcpHelloMessage_deleteMembers(&hello);
 
     /* Encode the message header at offset 0 */
     UA_TcpMessageHeader messageHeader;
     messageHeader.messageTypeAndChunkType = UA_CHUNKTYPE_FINAL + UA_MESSAGETYPE_HEL;
-    messageHeader.messageSize = (UA_UInt32)offset;
-    offset = 0;
-    retval |= UA_TcpMessageHeader_encodeBinary(&messageHeader, &message, &offset);
+    messageHeader.messageSize = (UA_UInt32)((uintptr_t)bufPos - (uintptr_t)message.data);
+    bufPos = message.data;
+    retval |= UA_TcpMessageHeader_encodeBinary(&messageHeader, &bufPos, &bufEnd);
     if(retval != UA_STATUSCODE_GOOD) {
         conn->releaseSendBuffer(conn, &message);
         return retval;
@@ -133,7 +134,7 @@ HelAckHandshake(UA_Client *client) {
     }
 
     /* Decode the message */
-    offset = 0;
+    size_t offset = 0;
     UA_TcpAcknowledgeMessage ackMessage;
     retval = UA_TcpMessageHeader_decodeBinary(&reply, &offset, &messageHeader);
     retval |= UA_TcpAcknowledgeMessage_decodeBinary(&reply, &offset, &ackMessage);
@@ -182,24 +183,25 @@ SecureChannelHandshake(UA_Client *client, UA_Boolean renew) {
         return retval;
 
     /* Jump over the messageHeader that will be encoded last */
-    size_t offset = 12;
+    UA_Byte *bufPos = &message.data[12];
+    const UA_Byte *bufEnd = &message.data[message.length];
 
     /* Encode the Asymmetric Security Header */
     UA_AsymmetricAlgorithmSecurityHeader asymHeader;
     UA_AsymmetricAlgorithmSecurityHeader_init(&asymHeader);
     asymHeader.securityPolicyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None");
-    retval = UA_AsymmetricAlgorithmSecurityHeader_encodeBinary(&asymHeader, &message, &offset);
+    retval = UA_AsymmetricAlgorithmSecurityHeader_encodeBinary(&asymHeader, &bufPos, &bufEnd);
 
     /* Encode the sequence header */
     UA_SequenceHeader seqHeader;
     seqHeader.sequenceNumber = ++client->channel.sendSequenceNumber;
     seqHeader.requestId = ++client->requestId;
-    retval |= UA_SequenceHeader_encodeBinary(&seqHeader, &message, &offset);
+    retval |= UA_SequenceHeader_encodeBinary(&seqHeader, &bufPos, &bufEnd);
 
     /* Encode the NodeId of the OpenSecureChannel Service */
     UA_NodeId requestType =
         UA_NODEID_NUMERIC(0, UA_TYPES[UA_TYPES_OPENSECURECHANNELREQUEST].binaryEncodingId);
-    retval |= UA_NodeId_encodeBinary(&requestType, &message, &offset);
+    retval |= UA_NodeId_encodeBinary(&requestType, &bufPos, &bufEnd);
 
     /* Encode the OpenSecureChannelRequest */
     UA_OpenSecureChannelRequest opnSecRq;
@@ -218,18 +220,19 @@ SecureChannelHandshake(UA_Client *client, UA_Boolean renew) {
     opnSecRq.securityMode = UA_MESSAGESECURITYMODE_NONE;
     opnSecRq.clientNonce = client->channel.clientNonce;
     opnSecRq.requestedLifetime = client->config.secureChannelLifeTime;
-    retval |= UA_OpenSecureChannelRequest_encodeBinary(&opnSecRq, &message, &offset);
+    retval |= UA_OpenSecureChannelRequest_encodeBinary(&opnSecRq, &bufPos, &bufEnd);
 
     /* Encode the message header at the beginning */
+    size_t length = (uintptr_t)(bufPos - message.data);
+    bufPos = message.data;
     UA_SecureConversationMessageHeader messageHeader;
     messageHeader.messageHeader.messageTypeAndChunkType = UA_MESSAGETYPE_OPN + UA_CHUNKTYPE_FINAL;
-    messageHeader.messageHeader.messageSize = (UA_UInt32)offset;
+    messageHeader.messageHeader.messageSize = (UA_UInt32)length;
     if(renew)
         messageHeader.secureChannelId = client->channel.securityToken.channelId;
     else
         messageHeader.secureChannelId = 0;
-    offset = 0;
-    retval |= UA_SecureConversationMessageHeader_encodeBinary(&messageHeader, &message, &offset);
+    retval |= UA_SecureConversationMessageHeader_encodeBinary(&messageHeader, &bufPos, &bufEnd);
 
     /* Clean up and return if encoding the message failed */
     if(retval != UA_STATUSCODE_GOOD) {
@@ -238,7 +241,7 @@ SecureChannelHandshake(UA_Client *client, UA_Boolean renew) {
     }
 
     /* Send the message */
-    message.length = messageHeader.messageHeader.messageSize;
+    message.length = length;
     retval = conn->send(conn, &message);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
@@ -255,7 +258,7 @@ SecureChannelHandshake(UA_Client *client, UA_Boolean renew) {
     }
 
     /* Decode the header */
-    offset = 0;
+    size_t offset = 0;
     retval = UA_SecureConversationMessageHeader_decodeBinary(&reply, &offset, &messageHeader);
     retval |= UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(&reply, &offset, &asymHeader);
     retval |= UA_SequenceHeader_decodeBinary(&reply, &offset, &seqHeader);
@@ -540,16 +543,21 @@ CloseSecureChannel(UA_Client *client) {
         return retval;
     }
 
-    size_t offset = 12;
-    retval |= UA_SymmetricAlgorithmSecurityHeader_encodeBinary(&symHeader, &message, &offset);
-    retval |= UA_SequenceHeader_encodeBinary(&seqHeader, &message, &offset);
-    retval |= UA_NodeId_encodeBinary(&typeId, &message, &offset);
+    /* Jump over the header */
+    UA_Byte *bufPos = &message.data[12];
+    const UA_Byte *bufEnd = &message.data[message.length];
+    
+    /* Encode some more headers and the CloseSecureChannelRequest */
+    retval |= UA_SymmetricAlgorithmSecurityHeader_encodeBinary(&symHeader, &bufPos, &bufEnd);
+    retval |= UA_SequenceHeader_encodeBinary(&seqHeader, &bufPos, &bufEnd);
+    retval |= UA_NodeId_encodeBinary(&typeId, &bufPos, &bufEnd);
     retval |= UA_encodeBinary(&request, &UA_TYPES[UA_TYPES_CLOSESECURECHANNELREQUEST],
-                              NULL, NULL, &message, &offset);
+                              &bufPos, &bufEnd, NULL, NULL);
 
-    msgHeader.messageHeader.messageSize = (UA_UInt32)offset;
-    offset = 0;
-    retval |= UA_SecureConversationMessageHeader_encodeBinary(&msgHeader, &message, &offset);
+    /* Encode the header */
+    msgHeader.messageHeader.messageSize = (UA_UInt32)((uintptr_t)bufPos - (uintptr_t)message.data);
+    bufPos = message.data;
+    retval |= UA_SecureConversationMessageHeader_encodeBinary(&msgHeader, &bufPos, &bufEnd);
 
     if(retval == UA_STATUSCODE_GOOD) {
         message.length = msgHeader.messageHeader.messageSize;

+ 13 - 11
src/server/ua_server_binary.c

@@ -260,9 +260,10 @@ static void processHEL(UA_Connection *connection, const UA_ByteString *msg, size
         return;
 
     /* Encode and send the response */
-    size_t tmpPos = 0;
-    UA_TcpMessageHeader_encodeBinary(&ackHeader, &ack_msg, &tmpPos);
-    UA_TcpAcknowledgeMessage_encodeBinary(&ackMessage, &ack_msg, &tmpPos);
+    UA_Byte *bufPos = ack_msg.data;
+    const UA_Byte *bufEnd = &ack_msg.data[ack_msg.length];
+    UA_TcpMessageHeader_encodeBinary(&ackHeader, &bufPos, &bufEnd);
+    UA_TcpAcknowledgeMessage_encodeBinary(&ackMessage, &bufPos, &bufEnd);
     ack_msg.length = ackHeader.messageSize;
     connection->send(connection, &ack_msg);
 }
@@ -332,13 +333,14 @@ processOPN(UA_Server *server, UA_Connection *connection,
     }
 
     /* Encode the message after the secureconversationmessageheader */
-    size_t tmpPos = 12; /* skip the header */
+    UA_Byte *bufPos = &resp_msg.data[12]; /* skip the header */
+    const UA_Byte *bufEnd = &resp_msg.data[resp_msg.length];
     seqHeader.sequenceNumber = UA_atomic_add(&channel->sendSequenceNumber, 1);
-    retval |= UA_AsymmetricAlgorithmSecurityHeader_encodeBinary(&asymHeader, &resp_msg, &tmpPos); // just mirror back
-    retval |= UA_SequenceHeader_encodeBinary(&seqHeader, &resp_msg, &tmpPos);
+    retval |= UA_AsymmetricAlgorithmSecurityHeader_encodeBinary(&asymHeader, &bufPos, &bufEnd); // just mirror back
+    retval |= UA_SequenceHeader_encodeBinary(&seqHeader, &bufPos, &bufEnd);
     UA_NodeId responseType = UA_NODEID_NUMERIC(0, UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE].binaryEncodingId);
-    retval |= UA_NodeId_encodeBinary(&responseType, &resp_msg, &tmpPos);
-    retval |= UA_OpenSecureChannelResponse_encodeBinary(&p, &resp_msg, &tmpPos);
+    retval |= UA_NodeId_encodeBinary(&responseType, &bufPos, &bufEnd);
+    retval |= UA_OpenSecureChannelResponse_encodeBinary(&p, &bufPos, &bufEnd);
 
     if(retval != UA_STATUSCODE_GOOD) {
         connection->releaseSendBuffer(connection, &resp_msg);
@@ -351,10 +353,10 @@ processOPN(UA_Server *server, UA_Connection *connection,
     /* Encode the secureconversationmessageheader (cannot fail) and send */
     UA_SecureConversationMessageHeader respHeader;
     respHeader.messageHeader.messageTypeAndChunkType = UA_MESSAGETYPE_OPN + UA_CHUNKTYPE_FINAL;
-    respHeader.messageHeader.messageSize = (UA_UInt32)tmpPos;
+    respHeader.messageHeader.messageSize = (u32)((uintptr_t)bufPos - (uintptr_t)resp_msg.data);
     respHeader.secureChannelId = p.securityToken.channelId;
-    tmpPos = 0;
-    UA_SecureConversationMessageHeader_encodeBinary(&respHeader, &resp_msg, &tmpPos);
+    bufPos = resp_msg.data;
+    UA_SecureConversationMessageHeader_encodeBinary(&respHeader, &bufPos, &bufEnd);
     resp_msg.length = respHeader.messageHeader.messageSize;
     connection->send(connection, &resp_msg);
 

+ 4 - 3
src/server/ua_subscription.c

@@ -84,14 +84,15 @@ detectValueChangeWithFilter(UA_MonitoredItem *mon, UA_DataValue *value,
         return false;
 
     /* Encode the value */
-    size_t encodingOffset = 0;
+    UA_Byte *bufPos = encoding->data;
+    const UA_Byte *bufEnd = &encoding->data[encoding->length];
     UA_StatusCode retval = UA_encodeBinary(value, &UA_TYPES[UA_TYPES_DATAVALUE],
-                                           NULL, NULL, encoding, &encodingOffset);
+                                           &bufPos, &bufEnd, NULL, NULL);
     if(retval != UA_STATUSCODE_GOOD)
         return false;
 
     /* The value has changed */
-    encoding->length = encodingOffset;
+    encoding->length = (uintptr_t)bufPos - (uintptr_t)encoding->data;
     return !mon->lastSampledValue.data || !UA_String_equal(encoding, &mon->lastSampledValue);
 }
 

+ 34 - 36
src/ua_securechannel.c

@@ -123,16 +123,16 @@ void UA_SecureChannel_revolveTokens(UA_SecureChannel *channel) {
 /***********************/
 
 static UA_StatusCode
-UA_SecureChannel_sendChunk(UA_ChunkInfo *ci, UA_ByteString *dst, size_t offset) {
+UA_SecureChannel_sendChunk(UA_ChunkInfo *ci, UA_Byte **bufPos, const UA_Byte **bufEnd) {
     UA_SecureChannel *channel = ci->channel;
     UA_Connection *connection = channel->connection;
     if(!connection)
        return UA_STATUSCODE_BADINTERNALERROR;
 
-    /* adjust the buffer where the header was hidden */
-    dst->data = &dst->data[-UA_SECURE_MESSAGE_HEADER_LENGTH];
-    dst->length += UA_SECURE_MESSAGE_HEADER_LENGTH;
-    offset += UA_SECURE_MESSAGE_HEADER_LENGTH;
+    /* Adjust the buffer where the header was hidden */
+    UA_ByteString *dst = &ci->buffer;
+    UA_Byte *chunkEndPos = *bufPos;
+    size_t offset = (uintptr_t)*bufPos - (uintptr_t)dst->data;
 
     if(ci->messageSizeSoFar + offset > connection->remoteConf.maxMessageSize &&
        connection->remoteConf.maxMessageSize > 0)
@@ -156,9 +156,10 @@ UA_SecureChannel_sendChunk(UA_ChunkInfo *ci, UA_ByteString *dst, size_t offset)
         respHeader.messageHeader.messageTypeAndChunkType += UA_CHUNKTYPE_ABORT;
         UA_String errorMsg;
         UA_String_init(&errorMsg);
-        offset = UA_SECURE_MESSAGE_HEADER_LENGTH;
-        UA_UInt32_encodeBinary(&ci->errorCode, dst, &offset);
-        UA_String_encodeBinary(&errorMsg, dst, &offset);
+        chunkEndPos = &dst->data[UA_SECURE_MESSAGE_HEADER_LENGTH];
+        UA_UInt32_encodeBinary(&ci->errorCode, &chunkEndPos, bufEnd);
+        UA_String_encodeBinary(&errorMsg, &chunkEndPos, bufEnd);
+        offset = (uintptr_t)*bufEnd - (uintptr_t)dst->data;
     }
     respHeader.messageHeader.messageSize = (UA_UInt32)offset;
     ci->messageSizeSoFar += offset;
@@ -169,10 +170,10 @@ UA_SecureChannel_sendChunk(UA_ChunkInfo *ci, UA_ByteString *dst, size_t offset)
     UA_SequenceHeader seqHeader;
     seqHeader.requestId = ci->requestId;
     seqHeader.sequenceNumber = UA_atomic_add(&channel->sendSequenceNumber, 1);
-    size_t offset_header = 0;
-    UA_SecureConversationMessageHeader_encodeBinary(&respHeader, dst, &offset_header);
-    UA_SymmetricAlgorithmSecurityHeader_encodeBinary(&symSecHeader, dst, &offset_header);
-    UA_SequenceHeader_encodeBinary(&seqHeader, dst, &offset_header);
+    UA_Byte *beginPos = dst->data;
+    UA_SecureConversationMessageHeader_encodeBinary(&respHeader, &beginPos, bufEnd);
+    UA_SymmetricAlgorithmSecurityHeader_encodeBinary(&symSecHeader, &beginPos, bufEnd);
+    UA_SequenceHeader_encodeBinary(&seqHeader, &beginPos, bufEnd);
 
     /* Send the chunk, the buffer is freed in the network layer */
     dst->length = offset; /* set the buffer length to the content length */
@@ -184,11 +185,9 @@ UA_SecureChannel_sendChunk(UA_ChunkInfo *ci, UA_ByteString *dst, size_t offset)
             connection->getSendBuffer(connection, connection->localConf.sendBufferSize, dst);
         if(retval != UA_STATUSCODE_GOOD)
             return retval;
-        /* Forward the data pointer so that the payload is encoded after the message header.
-         * TODO: This works but is a bit too clever. Instead, we could return an offset to the
-         * binary encoding exchangeBuffer function. */
-        dst->data = &dst->data[UA_SECURE_MESSAGE_HEADER_LENGTH];
-        dst->length = connection->localConf.sendBufferSize - UA_SECURE_MESSAGE_HEADER_LENGTH;
+        /* Forward the data pointer so that the payload is encoded after the message header. */
+        *bufPos = &dst->data[UA_SECURE_MESSAGE_HEADER_LENGTH];
+        *bufEnd = &dst->data[dst->length];
     }
     return ci->errorCode;
 }
@@ -200,53 +199,52 @@ UA_SecureChannel_sendBinaryMessage(UA_SecureChannel *channel, UA_UInt32 requestI
     if(!connection)
         return UA_STATUSCODE_BADINTERNALERROR;
 
+    /* Create the chunking info structure */
+    UA_ChunkInfo ci;
+    ci.channel = channel;
+    ci.requestId = requestId;
+    ci.chunksSoFar = 0;
+    ci.messageSizeSoFar = 0;
+    ci.final = false;
+    ci.messageType = UA_MESSAGETYPE_MSG;
+    ci.errorCode = UA_STATUSCODE_GOOD;
+
     /* Allocate the message buffer */
-    UA_ByteString message;
     UA_StatusCode retval =
-        connection->getSendBuffer(connection, connection->localConf.sendBufferSize, &message);
+        connection->getSendBuffer(connection, connection->localConf.sendBufferSize, &ci.buffer);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
 
     /* Hide the message beginning where the header will be encoded */
-    message.data = &message.data[UA_SECURE_MESSAGE_HEADER_LENGTH];
-    message.length -= UA_SECURE_MESSAGE_HEADER_LENGTH;
+    UA_Byte *bufPos = &ci.buffer.data[UA_SECURE_MESSAGE_HEADER_LENGTH];
+    const UA_Byte *bufEnd = &ci.buffer.data[ci.buffer.length];
 
     /* Encode the message type */
-    size_t messagePos = 0;
     UA_NodeId typeId = contentType->typeId; /* always numeric */
     typeId.identifier.numeric = contentType->binaryEncodingId;
-    UA_NodeId_encodeBinary(&typeId, &message, &messagePos);
+    UA_NodeId_encodeBinary(&typeId, &bufPos, &bufEnd);
 
     /* Encode with the chunking callback */
-    UA_ChunkInfo ci;
-    ci.channel = channel;
-    ci.requestId = requestId;
-    ci.chunksSoFar = 0;
-    ci.messageSizeSoFar = 0;
-    ci.final = false;
-    ci.messageType = UA_MESSAGETYPE_MSG;
-    ci.errorCode = UA_STATUSCODE_GOOD;
     if(typeId.identifier.numeric == 446 || typeId.identifier.numeric == 449)
         ci.messageType = UA_MESSAGETYPE_OPN;
     else if(typeId.identifier.numeric == 452 || typeId.identifier.numeric == 455)
         ci.messageType = UA_MESSAGETYPE_CLO;
-    retval = UA_encodeBinary(content, contentType,
-                             (UA_exchangeEncodeBuffer)UA_SecureChannel_sendChunk,
-                             &ci, &message, &messagePos);
+    retval = UA_encodeBinary(content, contentType, &bufPos, &bufEnd,
+                             (UA_exchangeEncodeBuffer)UA_SecureChannel_sendChunk, &ci);
 
     /* Encoding failed, release the message */
     if(retval != UA_STATUSCODE_GOOD) {
         if(!ci.final) {
             /* the abort message was not send */
             ci.errorCode = retval;
-            UA_SecureChannel_sendChunk(&ci, &message, messagePos);
+            UA_SecureChannel_sendChunk(&ci, &bufPos, &bufEnd);
         }
         return retval;
     }
 
     /* Encoding finished, send the final chunk */
     ci.final = UA_TRUE;
-    return UA_SecureChannel_sendChunk(&ci, &message, messagePos);
+    return UA_SecureChannel_sendChunk(&ci, &bufPos, &bufEnd);
 }
 
 /***************************/

+ 1 - 0
src/ua_securechannel.h

@@ -38,6 +38,7 @@ typedef struct {
     size_t messageSizeSoFar;
     UA_Boolean final;
     UA_StatusCode errorCode;
+    UA_ByteString buffer;
 } UA_ChunkInfo;
 
 struct UA_SecureChannel {

+ 16 - 30
src/ua_types_encoding_binary.c

@@ -56,10 +56,9 @@ extern const UA_calcSizeBinarySignature calcSizeBinaryJumpTable[UA_BUILTIN_TYPES
 UA_THREAD_LOCAL size_t customTypesArraySize;
 UA_THREAD_LOCAL const UA_DataType *customTypesArray;
 
-/* We give pointers to the current position and the last position in the buffer
- * instead of a string with an offset. */
-UA_THREAD_LOCAL UA_Byte * pos;
-UA_THREAD_LOCAL UA_Byte * end;
+/* Pointers to the current position and the last position in the buffer */
+UA_THREAD_LOCAL UA_Byte *pos;
+UA_THREAD_LOCAL const UA_Byte *end;
 
 /* In UA_encodeBinaryInternal, we store a pointer to the last "good" position in
  * the buffer. When encoding reaches the end of the buffer, send out a chunk
@@ -83,7 +82,6 @@ UA_THREAD_LOCAL UA_Byte * end;
  * DiagnosticInfo_encodeBinary */
 
 /* Thread-local buffers used for exchanging the buffer for chunking */
-UA_THREAD_LOCAL UA_ByteString *encodeBuf; /* the original buffer */
 UA_THREAD_LOCAL UA_exchangeEncodeBuffer exchangeBufferCallback;
 UA_THREAD_LOCAL void *exchangeBufferCallbackHandle;
 
@@ -93,24 +91,15 @@ exchangeBuffer(void) {
     if(!exchangeBufferCallback)
         return UA_STATUSCODE_BADENCODINGERROR;
 
-    /* Store context variables since chunk-sending might call UA_encode itself */
-    UA_ByteString *store_encodeBuf = encodeBuf;
+    /* Store context variables since exchangeBuffer might call UA_encode itself */
     UA_exchangeEncodeBuffer store_exchangeBufferCallback = exchangeBufferCallback;
     void *store_exchangeBufferCallbackHandle = exchangeBufferCallbackHandle;
 
-    size_t offset = ((uintptr_t)pos - (uintptr_t)encodeBuf->data) / sizeof(UA_Byte);
-    UA_StatusCode retval = exchangeBufferCallback(exchangeBufferCallbackHandle, encodeBuf, offset);
+    UA_StatusCode retval = exchangeBufferCallback(exchangeBufferCallbackHandle, &pos, &end);
 
-    /* Restore context variables. This restores the pointer to the buffer, not the buffer
-     * itself. This is required so that a call to UA_encode can be made from within the
-     * exchangeBufferCallback. For example to encode the chunk header */
-    encodeBuf = store_encodeBuf;
+    /* Restore context variables */
     exchangeBufferCallback = store_exchangeBufferCallback;
     exchangeBufferCallbackHandle = store_exchangeBufferCallbackHandle;
-
-    /* Set pos and end in order to continue encoding */
-    pos = encodeBuf->data;
-    end = &encodeBuf->data[encodeBuf->length];
     return retval;
 }
 
@@ -1456,22 +1445,19 @@ UA_encodeBinaryInternal(const void *src, const UA_DataType *type) {
 
 UA_StatusCode
 UA_encodeBinary(const void *src, const UA_DataType *type,
-                UA_exchangeEncodeBuffer exchangeCallback, void *exchangeHandle,
-                UA_ByteString *dst, size_t *offset) {
-    /* Set the (thread-local) position and end pointers to save function
-     * arguments */
-    pos = &dst->data[*offset];
-    end = &dst->data[dst->length];
-
-    /* Set the (thread-local) exchangeBufferCallbacks where the buffer is
-     * exchanged and the current chunk sent out */
-    encodeBuf = dst;
+                UA_Byte **bufPos, const UA_Byte **bufEnd,
+                UA_exchangeEncodeBuffer exchangeCallback, void *exchangeHandle) {
+    /* Set the (thread-local) pointers to save function arguments */
+    pos = *bufPos;
+    end = *bufEnd;
     exchangeBufferCallback = exchangeCallback;
     exchangeBufferCallbackHandle = exchangeHandle;
-
-    /* Encode and clean up */
     UA_StatusCode retval = UA_encodeBinaryInternal(src, type);
-    *offset = (size_t)(pos - dst->data) / sizeof(UA_Byte);
+
+    /* Set the current buffer position. Beware that the buffer might have been
+     * exchanged internally. */
+    *bufPos = pos;
+    *bufEnd = end;
     return retval;
 }
 

+ 3 - 3
src/ua_types_encoding_binary.h

@@ -7,12 +7,12 @@
 
 #include "ua_types.h"
 
-typedef UA_StatusCode (*UA_exchangeEncodeBuffer)(void *handle, UA_ByteString *buf, size_t offset);
+typedef UA_StatusCode (*UA_exchangeEncodeBuffer)(void *handle, UA_Byte **bufPos, const UA_Byte **bufEnd);
 
 UA_StatusCode
 UA_encodeBinary(const void *src, const UA_DataType *type,
-                UA_exchangeEncodeBuffer exchangeCallback, void *exchangeHandle,
-                UA_ByteString *dst, size_t *offset) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+                UA_Byte **bufPos, const UA_Byte **bufEnd,
+                UA_exchangeEncodeBuffer exchangeCallback, void *exchangeHandle) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
 
 UA_StatusCode
 UA_decodeBinary(const UA_ByteString *src, size_t *offset, void *dst,

+ 22 - 16
tests/check_chunking.c

@@ -17,18 +17,17 @@ size_t counter;
 size_t dataCount;
 
 static UA_StatusCode
-sendChunkMockUp(UA_ChunkInfo *ci, UA_ByteString *dst, size_t offset) {
+sendChunkMockUp(UA_ChunkInfo *ci, UA_Byte **bufPos, const UA_Byte **bufEnd) {
+    size_t offset = (uintptr_t)(*bufPos - buffers[bufIndex].data);
     bufIndex++;
-    dst->data = buffers[bufIndex].data;
-    dst->length = buffers[bufIndex].length;
+    *bufPos = buffers[bufIndex].data;
+    *bufEnd = &(*bufPos)[buffers[bufIndex].length];
     counter++;
     dataCount += offset;
     return UA_STATUSCODE_GOOD;
 }
 START_TEST(encodeArrayIntoFiveChunksShallWork) {
-
     size_t arraySize = 30; //number of elements within the array which should be encoded
-    size_t offset = 0; // encoding offset
     size_t chunkCount = 6; // maximum chunk count
     size_t chunkSize = 30; //size in bytes of each chunk
     UA_ChunkInfo ci;
@@ -49,14 +48,15 @@ START_TEST(encodeArrayIntoFiveChunksShallWork) {
     UA_Variant v;
     UA_Variant_setArrayCopy(&v,ar,arraySize,&UA_TYPES[UA_TYPES_INT32]);
 
-    UA_StatusCode retval = UA_encodeBinary(&v,&UA_TYPES[UA_TYPES_VARIANT],
-                                           (UA_exchangeEncodeBuffer)sendChunkMockUp,
-                                           &ci,&workingBuffer,&offset);
+    UA_Byte *pos = workingBuffer.data;
+    const UA_Byte *end = &workingBuffer.data[workingBuffer.length];
+    UA_StatusCode retval = UA_encodeBinary(&v,&UA_TYPES[UA_TYPES_VARIANT], &pos, &end,
+                                           (UA_exchangeEncodeBuffer)sendChunkMockUp, &ci);
 
     ck_assert_uint_eq(retval,UA_STATUSCODE_GOOD);
     ck_assert_int_eq(counter,4); //5 chunks allocated - callback called 4 times
 
-    dataCount += offset; //last piece of data - no callback was called
+    dataCount += (uintptr_t)(pos - buffers[bufIndex].data);
     ck_assert_int_eq(UA_calcSizeBinary(&v,&UA_TYPES[UA_TYPES_VARIANT]), dataCount);
 
     UA_Variant_deleteMembers(&v);
@@ -69,7 +69,6 @@ END_TEST
 START_TEST(encodeStringIntoFiveChunksShallWork) {
 
     size_t stringLength = 120; //number of elements within the array which should be encoded
-    size_t offset = 0; // encoding offset
     size_t chunkCount = 6; // maximum chunk count
     size_t chunkSize = 30; //size in bytes of each chunk
 
@@ -97,12 +96,15 @@ START_TEST(encodeStringIntoFiveChunksShallWork) {
     UA_Variant v;
     UA_Variant_setScalarCopy(&v,&string,&UA_TYPES[UA_TYPES_STRING]);
 
-    UA_StatusCode retval = UA_encodeBinary(&v,&UA_TYPES[UA_TYPES_VARIANT],(UA_exchangeEncodeBuffer)sendChunkMockUp,&ci,&workingBuffer,&offset);
+    UA_Byte *pos = workingBuffer.data;
+    const UA_Byte *end = &workingBuffer.data[workingBuffer.length];
+    UA_StatusCode retval = UA_encodeBinary(&v, &UA_TYPES[UA_TYPES_VARIANT], &pos, &end,
+                                           (UA_exchangeEncodeBuffer)sendChunkMockUp, &ci);
 
     ck_assert_uint_eq(retval,UA_STATUSCODE_GOOD);
     ck_assert_int_eq(counter,4); //5 chunks allocated - callback called 4 times
 
-    dataCount += offset; //last piece of data - no callback was called
+    dataCount += (uintptr_t)(pos - buffers[bufIndex].data);
     ck_assert_int_eq(UA_calcSizeBinary(&v,&UA_TYPES[UA_TYPES_VARIANT]), dataCount);
 
     UA_Variant_deleteMembers(&v);
@@ -114,7 +116,6 @@ END_TEST
 START_TEST(encodeTwoStringsIntoTenChunksShallWork) {
 
     size_t stringLength = 143; //number of elements within the array which should be encoded
-    size_t offset = 0; // encoding offset
     size_t chunkCount = 10; // maximum chunk count
     size_t chunkSize = 30; //size in bytes of each chunk
 
@@ -140,13 +141,18 @@ START_TEST(encodeTwoStringsIntoTenChunksShallWork) {
         string.data[i] =  tmpString[tmp];
     }
 
-    UA_StatusCode retval = UA_encodeBinary(&string,&UA_TYPES[UA_TYPES_STRING],(UA_exchangeEncodeBuffer)sendChunkMockUp,&ci,&workingBuffer,&offset);
+    UA_Byte *pos = workingBuffer.data;
+    const UA_Byte *end = &workingBuffer.data[workingBuffer.length];
+    UA_StatusCode retval = UA_encodeBinary(&string, &UA_TYPES[UA_TYPES_STRING], &pos, &end,
+                                           (UA_exchangeEncodeBuffer)sendChunkMockUp, &ci);
     ck_assert_uint_eq(retval,UA_STATUSCODE_GOOD);
     ck_assert_int_eq(counter,4); //5 chunks allocated - callback called 4 times
+    size_t offset = (uintptr_t)(pos - buffers[bufIndex].data);
     ck_assert_int_eq(UA_calcSizeBinary(&string,&UA_TYPES[UA_TYPES_STRING]), dataCount + offset);
 
-    retval = UA_encodeBinary(&string,&UA_TYPES[UA_TYPES_STRING],(UA_exchangeEncodeBuffer)sendChunkMockUp,&ci,&workingBuffer,&offset);
-    dataCount += offset; //last piece of data - no callback was called
+    retval = UA_encodeBinary(&string,&UA_TYPES[UA_TYPES_STRING], &pos, &end,
+                             (UA_exchangeEncodeBuffer)sendChunkMockUp, &ci);
+    dataCount += (uintptr_t)(pos - buffers[bufIndex].data);
     ck_assert_uint_eq(retval,UA_STATUSCODE_GOOD);
     ck_assert_int_eq(counter,9); //10 chunks allocated - callback called 4 times
     ck_assert_int_eq(2 * UA_calcSizeBinary(&string,&UA_TYPES[UA_TYPES_STRING]), dataCount);

+ 56 - 58
tests/check_services_view.c

@@ -48,75 +48,73 @@ static void teardown_server(void) {
 }
 
 
-START_TEST(Service_Browse_WithBrowseName)
-    {
-        UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
+START_TEST(Service_Browse_WithBrowseName) {
+    UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
 
-        UA_BrowseDescription bd;
-        UA_BrowseDescription_init(&bd);
-        bd.resultMask = UA_BROWSERESULTMASK_BROWSENAME;
-        bd.nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
-        bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
-        bd.browseDirection = UA_BROWSEDIRECTION_FORWARD;
+    UA_BrowseDescription bd;
+    UA_BrowseDescription_init(&bd);
+    bd.resultMask = UA_BROWSERESULTMASK_BROWSENAME;
+    bd.nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
+    bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
+    bd.browseDirection = UA_BROWSEDIRECTION_FORWARD;
 
-        UA_BrowseResult br = UA_Server_browse(server, 0, &bd);
+    UA_BrowseResult br = UA_Server_browse(server, 0, &bd);
 
-        ck_assert_int_eq(br.statusCode, UA_STATUSCODE_GOOD);
-        ck_assert(br.referencesSize > 0);
-        ck_assert(!UA_String_equal(&br.references[0].browseName.name, &UA_STRING_NULL));
+    ck_assert_int_eq(br.statusCode, UA_STATUSCODE_GOOD);
+    ck_assert(br.referencesSize > 0);
+    ck_assert(!UA_String_equal(&br.references[0].browseName.name, &UA_STRING_NULL));
 
-        UA_BrowseResult_deleteMembers(&br);
-        UA_Server_delete(server);
-    }
+    UA_BrowseResult_deleteMembers(&br);
+    UA_Server_delete(server);
+}
 END_TEST
 
-START_TEST(Service_TranslateBrowsePathsToNodeIds)
-    {
-        UA_Client *client = UA_Client_new(UA_ClientConfig_standard);
+START_TEST(Service_TranslateBrowsePathsToNodeIds) {
+    UA_Client *client = UA_Client_new(UA_ClientConfig_standard);
 
-        UA_StatusCode retVal = UA_Client_connect(client, "opc.tcp://localhost:16664");
-        ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD);
+    UA_StatusCode retVal = UA_Client_connect(client, "opc.tcp://localhost:16664");
+    ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD);
 
-        // Just for testing we want to translate the following path to its corresponding node id
-        // /Objects/Server/ServerStatus/State
-        // Equals the following node IDs:
-        // /85/2253/2256/2259
+    // Just for testing we want to translate the following path to its corresponding node id
+    // /Objects/Server/ServerStatus/State
+    // Equals the following node IDs:
+    // /85/2253/2256/2259
 
 #define BROWSE_PATHS_SIZE 3
-        char *paths[BROWSE_PATHS_SIZE] = {"Server", "ServerStatus", "State"};
-        UA_UInt32 ids[BROWSE_PATHS_SIZE] = {UA_NS0ID_ORGANIZES, UA_NS0ID_HASCOMPONENT, UA_NS0ID_HASCOMPONENT};
-        UA_BrowsePath browsePath;
-        UA_BrowsePath_init(&browsePath);
-        browsePath.startingNode = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
-        browsePath.relativePath.elements = UA_Array_new(BROWSE_PATHS_SIZE, &UA_TYPES[UA_TYPES_RELATIVEPATHELEMENT]);
-        browsePath.relativePath.elementsSize = BROWSE_PATHS_SIZE;
-
-        for(size_t i = 0; i < BROWSE_PATHS_SIZE; i++) {
-            UA_RelativePathElement *elem = &browsePath.relativePath.elements[i];
-            elem->referenceTypeId = UA_NODEID_NUMERIC(0, ids[i]);
-            elem->targetName = UA_QUALIFIEDNAME_ALLOC(0, paths[i]);
-        }
-
-        UA_TranslateBrowsePathsToNodeIdsRequest request;
-        UA_TranslateBrowsePathsToNodeIdsRequest_init(&request);
-        request.browsePaths = &browsePath;
-        request.browsePathsSize = 1;
-
-        UA_TranslateBrowsePathsToNodeIdsResponse response = UA_Client_Service_translateBrowsePathsToNodeIds(client, request);
-
-        ck_assert_int_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
-        ck_assert_int_eq(response.resultsSize, 1);
-
-        ck_assert_int_eq(response.results[0].targetsSize, 1);
-        ck_assert_int_eq(response.results[0].targets[0].targetId.nodeId.identifierType, UA_NODEIDTYPE_NUMERIC);
-        ck_assert_int_eq(response.results[0].targets[0].targetId.nodeId.identifier.numeric, UA_NS0ID_SERVER_SERVERSTATUS_STATE);
-
-        UA_BrowsePath_deleteMembers(&browsePath);
-        UA_TranslateBrowsePathsToNodeIdsResponse_deleteMembers(&response);
-        retVal = UA_Client_disconnect(client);
-        ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD);
-        UA_Client_delete(client);
+    char *paths[BROWSE_PATHS_SIZE] = {"Server", "ServerStatus", "State"};
+    UA_UInt32 ids[BROWSE_PATHS_SIZE] = {UA_NS0ID_ORGANIZES, UA_NS0ID_HASCOMPONENT, UA_NS0ID_HASCOMPONENT};
+    UA_BrowsePath browsePath;
+    UA_BrowsePath_init(&browsePath);
+    browsePath.startingNode = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
+    browsePath.relativePath.elements = UA_Array_new(BROWSE_PATHS_SIZE, &UA_TYPES[UA_TYPES_RELATIVEPATHELEMENT]);
+    browsePath.relativePath.elementsSize = BROWSE_PATHS_SIZE;
+
+    for(size_t i = 0; i < BROWSE_PATHS_SIZE; i++) {
+        UA_RelativePathElement *elem = &browsePath.relativePath.elements[i];
+        elem->referenceTypeId = UA_NODEID_NUMERIC(0, ids[i]);
+        elem->targetName = UA_QUALIFIEDNAME_ALLOC(0, paths[i]);
     }
+
+    UA_TranslateBrowsePathsToNodeIdsRequest request;
+    UA_TranslateBrowsePathsToNodeIdsRequest_init(&request);
+    request.browsePaths = &browsePath;
+    request.browsePathsSize = 1;
+
+    UA_TranslateBrowsePathsToNodeIdsResponse response = UA_Client_Service_translateBrowsePathsToNodeIds(client, request);
+
+    ck_assert_int_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
+    ck_assert_int_eq(response.resultsSize, 1);
+
+    ck_assert_int_eq(response.results[0].targetsSize, 1);
+    ck_assert_int_eq(response.results[0].targets[0].targetId.nodeId.identifierType, UA_NODEIDTYPE_NUMERIC);
+    ck_assert_int_eq(response.results[0].targets[0].targetId.nodeId.identifier.numeric, UA_NS0ID_SERVER_SERVERSTATUS_STATE);
+
+    UA_BrowsePath_deleteMembers(&browsePath);
+    UA_TranslateBrowsePathsToNodeIdsResponse_deleteMembers(&response);
+    retVal = UA_Client_disconnect(client);
+    ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD);
+    UA_Client_delete(client);
+}
 END_TEST
 
 static Suite *testSuite_Service_TranslateBrowsePathsToNodeIds(void) {

+ 100 - 130
tests/check_types_builtin.c

@@ -539,33 +539,30 @@ END_TEST
 
 START_TEST(UA_Byte_encode_test) {
     // given
-    UA_Byte src;
+    UA_Byte src       = 8;
     UA_Byte data[]    = { 0x00, 0xFF };
     UA_ByteString dst = { 2, data };
-
-    UA_Int32 retval = 0;
-    size_t pos = 0;
-
     ck_assert_uint_eq(dst.data[1], 0xFF);
 
-    src    = 8;
-    retval = UA_Byte_encodeBinary(&src, &dst, &pos);
+    UA_Byte *pos = dst.data;
+    const UA_Byte *end = &dst.data[dst.length];
+    UA_StatusCode retval = UA_Byte_encodeBinary(&src, &pos, &end);
 
     ck_assert_uint_eq(dst.data[0], 0x08);
     ck_assert_uint_eq(dst.data[1], 0xFF);
-    ck_assert_int_eq(pos, 1);
+    ck_assert_int_eq((uintptr_t)(pos - dst.data), 1);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 
     // Test2
     // given
     src = 0xFF;
     dst.data[1] = 0x00;
-    pos         = 0;
-    retval      = UA_Byte_encodeBinary(&src, &dst, &pos);
+    pos = dst.data;
+    retval      = UA_Byte_encodeBinary(&src, &pos, &end);
 
     ck_assert_int_eq(dst.data[0], 0xFF);
     ck_assert_int_eq(dst.data[1], 0x00);
-    ck_assert_int_eq(pos, 1);
+    ck_assert_int_eq((uintptr_t)(pos - dst.data), 1);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 
 }
@@ -573,27 +570,25 @@ END_TEST
 
 START_TEST(UA_UInt16_encodeNegativeShallEncodeLittleEndian) {
     // given
-    UA_UInt16     src;
+    UA_UInt16     src    = -1;
     UA_Byte       data[] = { 0x55, 0x55, 0x55, 0x55 };
     UA_ByteString dst    = { 4, data };
-
-    UA_StatusCode retval = 0;
-    size_t pos = 0;
+    UA_Byte *pos = dst.data;
+    const UA_Byte *end = &dst.data[dst.length];
 
     // when test 1
-    src    = -1;
-    retval = UA_UInt16_encodeBinary(&src, &dst, &pos);
+    UA_StatusCode retval = UA_UInt16_encodeBinary(&src, &pos, &end);
     // then test 1
-    ck_assert_int_eq(pos, 2);
+    ck_assert_int_eq((uintptr_t)(pos - dst.data), 2);
     ck_assert_int_eq(dst.data[0], 0xFF);
     ck_assert_int_eq(dst.data[1], 0xFF);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 
     // when test 2
     src    = -32768;
-    retval = UA_UInt16_encodeBinary(&src, &dst, &pos);
+    retval = UA_UInt16_encodeBinary(&src, &pos, &end);
     // then test 2
-    ck_assert_int_eq(pos, 4);
+    ck_assert_int_eq((uintptr_t)(pos - dst.data), 4);
     ck_assert_int_eq(dst.data[2], 0x00);
     ck_assert_int_eq(dst.data[3], 0x80);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
@@ -602,28 +597,25 @@ END_TEST
 
 START_TEST(UA_UInt16_encodeShallEncodeLittleEndian) {
     // given
-    UA_UInt16     src;
-    UA_Byte       data[] = {  0x55, 0x55,
-            0x55,       0x55 };
+    UA_UInt16     src    = 0;
+    UA_Byte       data[] = {  0x55, 0x55, 0x55, 0x55 };
     UA_ByteString dst    = { 4, data };
-
-    UA_StatusCode retval = 0;
-    size_t pos = 0;
+    UA_Byte *pos = dst.data;
+    const UA_Byte *end = &dst.data[dst.length];
 
     // when test 1
-    src    = 0;
-    retval = UA_UInt16_encodeBinary(&src, &dst, &pos);
+    UA_StatusCode retval = UA_UInt16_encodeBinary(&src, &pos, &end);
     // then test 1
-    ck_assert_int_eq(pos, 2);
+    ck_assert_int_eq((uintptr_t)(pos - dst.data), 2);
     ck_assert_int_eq(dst.data[0], 0x00);
     ck_assert_int_eq(dst.data[1], 0x00);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 
     // when test 2
     src    = 32767;
-    retval = UA_UInt16_encodeBinary(&src, &dst, &pos);
+    retval = UA_UInt16_encodeBinary(&src, &pos, &end);
     // then test 2
-    ck_assert_int_eq(pos, 4);
+    ck_assert_int_eq((uintptr_t)(pos - dst.data), 4);
     ck_assert_int_eq(dst.data[2], 0xFF);
     ck_assert_int_eq(dst.data[3], 0x7F);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
@@ -632,18 +624,16 @@ END_TEST
 
 START_TEST(UA_UInt32_encodeShallEncodeLittleEndian) {
     // given
-    UA_UInt32     src;
+    UA_UInt32     src    = -1;
     UA_Byte       data[] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 };
     UA_ByteString dst    = { 8, data };
-
-    UA_StatusCode retval = 0;
-    size_t pos = 0;
+    UA_Byte *pos = dst.data;
+    const UA_Byte *end = &dst.data[dst.length];
 
     // when test 1
-    src    = -1;
-    retval = UA_UInt32_encodeBinary(&src, &dst, &pos);
+    UA_StatusCode retval = UA_UInt32_encodeBinary(&src, &pos, &end);
     // then test 1
-    ck_assert_int_eq(pos, 4);
+    ck_assert_int_eq((uintptr_t)(pos - dst.data), 4);
     ck_assert_int_eq(dst.data[0], 0xFF);
     ck_assert_int_eq(dst.data[1], 0xFF);
     ck_assert_int_eq(dst.data[2], 0xFF);
@@ -652,9 +642,9 @@ START_TEST(UA_UInt32_encodeShallEncodeLittleEndian) {
 
     // when test 2
     src    = 0x0101FF00;
-    retval = UA_UInt32_encodeBinary(&src, &dst, &pos);
+    retval = UA_UInt32_encodeBinary(&src, &pos, &end);
     // then test 2
-    ck_assert_int_eq(pos, 8);
+    ck_assert_int_eq((uintptr_t)(pos - dst.data), 8);
     ck_assert_int_eq(dst.data[4], 0x00);
     ck_assert_int_eq(dst.data[5], 0xFF);
     ck_assert_int_eq(dst.data[6], 0x01);
@@ -665,18 +655,16 @@ END_TEST
 
 START_TEST(UA_Int32_encodeShallEncodeLittleEndian) {
     // given
-    UA_Int32 src;
+    UA_Int32 src    = 1;
     UA_Byte  data[]   = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 };
     UA_ByteString dst = { 8, data };
-
-    UA_Int32 retval = 0;
-    size_t pos = 0;
+    UA_Byte *pos = dst.data;
+    const UA_Byte *end = &dst.data[dst.length];
 
     // when test 1
-    src    = 1;
-    retval = UA_Int32_encodeBinary(&src, &dst, &pos);
+    UA_StatusCode retval = UA_Int32_encodeBinary(&src, &pos, &end);
     // then test 1
-    ck_assert_int_eq(pos, 4);
+    ck_assert_int_eq((uintptr_t)(pos - dst.data), 4);
     ck_assert_int_eq(dst.data[0], 0x01);
     ck_assert_int_eq(dst.data[1], 0x00);
     ck_assert_int_eq(dst.data[2], 0x00);
@@ -685,9 +673,9 @@ START_TEST(UA_Int32_encodeShallEncodeLittleEndian) {
 
     // when test 2
     src    = 0x7FFFFFFF;
-    retval = UA_Int32_encodeBinary(&src, &dst, &pos);
+    retval = UA_Int32_encodeBinary(&src, &pos, &end);
     // then test 2
-    ck_assert_int_eq(pos, 8);
+    ck_assert_int_eq((uintptr_t)(pos - dst.data), 8);
     ck_assert_int_eq(dst.data[4], 0xFF);
     ck_assert_int_eq(dst.data[5], 0xFF);
     ck_assert_int_eq(dst.data[6], 0xFF);
@@ -698,19 +686,16 @@ END_TEST
 
 START_TEST(UA_Int32_encodeNegativeShallEncodeLittleEndian) {
     // given
-    UA_Int32 src;
-    UA_Byte  data[]   = {  0x55, 0x55,    0x55,  0x55,
-            0x55,  0x55,    0x55,  0x55 };
+    UA_Int32 src    = -1;
+    UA_Byte  data[]   = {  0x55, 0x55,    0x55,  0x55, 0x55,  0x55,    0x55,  0x55 };
     UA_ByteString dst = { 8, data };
-
-    UA_Int32  retval  = 0;
-    size_t pos = 0;
+    UA_Byte *pos = dst.data;
+    const UA_Byte *end = &dst.data[dst.length];
 
     // when test 1
-    src    = -1;
-    retval = UA_Int32_encodeBinary(&src, &dst, &pos);
+    UA_StatusCode retval = UA_Int32_encodeBinary(&src, &pos, &end);
     // then test 1
-    ck_assert_int_eq(pos, 4);
+    ck_assert_int_eq((uintptr_t)(pos - dst.data), 4);
     ck_assert_int_eq(dst.data[0], 0xFF);
     ck_assert_int_eq(dst.data[1], 0xFF);
     ck_assert_int_eq(dst.data[2], 0xFF);
@@ -721,19 +706,17 @@ END_TEST
 
 START_TEST(UA_UInt64_encodeShallWorkOnExample) {
     // given
-    UA_UInt64     src;
+    UA_UInt64     src    = -1;
     UA_Byte       data[] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
                              0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 };
     UA_ByteString dst    = { 16, data };
-
-    UA_StatusCode retval = 0;
-    size_t pos    = 0;
+    UA_Byte *pos = dst.data;
+    const UA_Byte *end = &dst.data[dst.length];
 
     // when test 1
-    src    = -1;
-    retval = UA_UInt64_encodeBinary(&src, &dst, &pos);
+    UA_StatusCode retval = UA_UInt64_encodeBinary(&src, &pos, &end);
     // then test 1
-    ck_assert_int_eq(pos, 8);
+    ck_assert_int_eq((uintptr_t)(pos - dst.data), 8);
     ck_assert_int_eq(dst.data[0], 0xFF);
     ck_assert_int_eq(dst.data[1], 0xFF);
     ck_assert_int_eq(dst.data[2], 0xFF);
@@ -746,9 +729,9 @@ START_TEST(UA_UInt64_encodeShallWorkOnExample) {
 
     // when test 2
     src    = 0x7F0033AA44EE6611;
-    retval = UA_UInt64_encodeBinary(&src, &dst, &pos);
+    retval = UA_UInt64_encodeBinary(&src, &pos, &end);
     // then test 2
-    ck_assert_int_eq(pos, 16);
+    ck_assert_int_eq((uintptr_t)(pos - dst.data), 16);
     ck_assert_int_eq(dst.data[8], 0x11);
     ck_assert_int_eq(dst.data[9], 0x66);
     ck_assert_int_eq(dst.data[10], 0xEE);
@@ -763,19 +746,17 @@ END_TEST
 
 START_TEST(UA_Int64_encodeShallEncodeLittleEndian) {
     // given
-    UA_Int64 src;
-    UA_Byte  data[]   = {  0x55, 0x55,    0x55,  0x55,    0x55,    0x55,  0x55,       0x55,
-            0x55,  0x55,    0x55,  0x55,    0x55,    0x55,  0x55,       0x55 };
+    UA_Int64 src    = 0x7F0033AA44EE6611;
+    UA_Byte  data[]   = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+                          0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 };
     UA_ByteString dst = { 16, data };
-
-    UA_Int32  retval  = 0;
-    size_t pos     = 0;
+    UA_Byte *pos = dst.data;
+    const UA_Byte *end = &dst.data[dst.length];
 
     // when test 1
-    src    = 0x7F0033AA44EE6611;
-    retval = UA_Int64_encodeBinary(&src, &dst, &pos);
+    UA_StatusCode retval = UA_Int64_encodeBinary(&src, &pos, &end);
     // then test 1
-    ck_assert_int_eq(pos, 8);
+    ck_assert_int_eq((uintptr_t)(pos - dst.data), 8);
     ck_assert_int_eq(dst.data[0], 0x11);
     ck_assert_int_eq(dst.data[1], 0x66);
     ck_assert_int_eq(dst.data[2], 0xEE);
@@ -790,19 +771,17 @@ END_TEST
 
 START_TEST(UA_Int64_encodeNegativeShallEncodeLittleEndian) {
     // given
-    UA_Int64 src;
-    UA_Byte  data[]   = {  0x55, 0x55,    0x55,  0x55,    0x55,    0x55,  0x55,       0x55,
-            0x55,  0x55,    0x55,  0x55,    0x55,    0x55,  0x55,       0x55 };
+    UA_Int64 src    = -1;
+    UA_Byte  data[]   = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+                          0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 };
     UA_ByteString dst = { 16, data };
-
-    UA_Int32  retval  = 0;
-    size_t pos     = 0;
+    UA_Byte *pos = dst.data;
+    const UA_Byte *end = &dst.data[dst.length];
 
     // when test 1
-    src    = -1;
-    retval = UA_Int64_encodeBinary(&src, &dst, &pos);
+    UA_StatusCode retval = UA_Int64_encodeBinary(&src, &pos, &end);
     // then test 1
-    ck_assert_int_eq(pos, 8);
+    ck_assert_int_eq((uintptr_t)(pos - dst.data), 8);
     ck_assert_int_eq(dst.data[0], 0xFF);
     ck_assert_int_eq(dst.data[1], 0xFF);
     ck_assert_int_eq(dst.data[2], 0xFF);
@@ -834,11 +813,12 @@ START_TEST(UA_Float_encodeShallWorkOnExample) {
 
     UA_Byte data[] = {0x55, 0x55, 0x55,  0x55};
     UA_ByteString dst = {4, data};
+    const UA_Byte *end = &dst.data[dst.length];
 
     for(size_t i = 0; i < 7; i++) {
-        size_t pos = 0;
-        UA_Int32 retval = UA_Float_encodeBinary(&src[i], &dst, &pos);
-        ck_assert_int_eq(pos, 4);
+        UA_Byte *pos = dst.data;
+        UA_Int32 retval = UA_Float_encodeBinary(&src[i], &pos, &end);
+        ck_assert_int_eq((uintptr_t)(pos - dst.data), 4);
         ck_assert_int_eq(dst.data[0], result[i][0]);
         ck_assert_int_eq(dst.data[1], result[i][1]);
         ck_assert_int_eq(dst.data[2], result[i][2]);
@@ -848,27 +828,23 @@ START_TEST(UA_Float_encodeShallWorkOnExample) {
 }
 END_TEST
 
-START_TEST(UA_Double_encodeShallWorkOnExample)
-   {
+START_TEST(UA_Double_encodeShallWorkOnExample) {
     // given
-    UA_Double src;
-    UA_Byte data[] = {  0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
-                        0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55
-                    };
+    UA_Double src = -6.5;
+    UA_Byte data[] = { 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
+                       0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55 };
     UA_ByteString dst = {16,data};
-
-    UA_Int32 retval;
-    size_t pos = 0;
+    UA_Byte *pos = dst.data;
+    const UA_Byte *end = &dst.data[dst.length];
 
     // when test 1
-    src = -6.5;
-    retval = UA_Double_encodeBinary(&src, &dst, &pos);
+    UA_StatusCode retval = UA_Double_encodeBinary(&src, &pos, &end);
     // then test 1
-    ck_assert_int_eq(pos, 8);
+    ck_assert_int_eq((uintptr_t)(pos - dst.data), 8);
     ck_assert_int_eq(dst.data[6], 0x1A);
     ck_assert_int_eq(dst.data[7], 0xC0);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
-   }
+}
 END_TEST
 
 START_TEST(UA_String_encodeShallWorkOnExample) {
@@ -878,19 +854,18 @@ START_TEST(UA_String_encodeShallWorkOnExample) {
     UA_Byte   mem[11] = "ACPLT OPCUA";
     src.data   = mem;
 
-    UA_Byte data[] = {  0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,      0x55,
-            0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,      0x55,
-            0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,      0x55 };
+    UA_Byte data[] = {  0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+                        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+                        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 };
     UA_ByteString dst = { 24, data };
-
-    UA_Int32  retval  = 0;
-    size_t pos     = 0;
+    UA_Byte *pos = dst.data;
+    const UA_Byte *end = &dst.data[dst.length];
 
     // when
-    retval = UA_String_encodeBinary(&src, &dst, &pos);
+    UA_StatusCode retval = UA_String_encodeBinary(&src, &pos, &end);
     // then
-    ck_assert_int_eq(pos, sizeof(UA_Int32)+11);
-    ck_assert_uint_eq(pos, UA_calcSizeBinary(&src, &UA_TYPES[UA_TYPES_STRING]));
+    ck_assert_int_eq((uintptr_t)(pos - dst.data), sizeof(UA_Int32)+11);
+    ck_assert_uint_eq(sizeof(UA_Int32)+11, UA_calcSizeBinary(&src, &UA_TYPES[UA_TYPES_STRING]));
     ck_assert_int_eq(dst.data[0], 11);
     ck_assert_int_eq(dst.data[sizeof(UA_Int32)+0], 'A');
     ck_assert_int_eq(dst.data[sizeof(UA_Int32)+1], 'C');
@@ -912,15 +887,15 @@ START_TEST(UA_ExpandedNodeId_encodeShallWorkOnExample) {
                        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
                        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 };
     UA_ByteString dst = { 32, data };
-    UA_Int32  retval = 0;
-    size_t pos = 0;
+    UA_Byte *pos = dst.data;
+    const UA_Byte *end = &dst.data[dst.length];
 
     // when
-    retval = UA_ExpandedNodeId_encodeBinary(&src, &dst, &pos);
+    UA_StatusCode retval = UA_ExpandedNodeId_encodeBinary(&src, &pos, &end);
     // then
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
-    ck_assert_int_eq(pos, 13);
-    ck_assert_uint_eq(pos, UA_calcSizeBinary(&src, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]));
+    ck_assert_int_eq((uintptr_t)(pos - dst.data), 13);
+    ck_assert_uint_eq(13, UA_calcSizeBinary(&src, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]));
     ck_assert_int_eq(dst.data[0], 0x80); // namespaceuri flag
 }
 END_TEST
@@ -936,15 +911,14 @@ START_TEST(UA_DataValue_encodeShallWorkOnExampleWithoutVariant) {
                        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
                        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 };
     UA_ByteString dst = { 24, data };
-
-    UA_Int32 retval = 0;
-    size_t pos     = 0;
+    UA_Byte *pos = dst.data;
+    const UA_Byte *end = &dst.data[dst.length];
 
     // when
-    retval = UA_DataValue_encodeBinary(&src, &dst, &pos);
+    UA_StatusCode retval = UA_DataValue_encodeBinary(&src, &pos, &end);
     // then
-    ck_assert_int_eq(pos, 9);            // represents the length
-    ck_assert_uint_eq(pos, UA_calcSizeBinary(&src, &UA_TYPES[UA_TYPES_DATAVALUE]));
+    ck_assert_int_eq((uintptr_t)(pos - dst.data), 9);
+    ck_assert_uint_eq(9, UA_calcSizeBinary(&src, &UA_TYPES[UA_TYPES_DATAVALUE]));
     ck_assert_int_eq(dst.data[0], 0x08); // encodingMask
     ck_assert_int_eq(dst.data[1], 80);   // 8 Byte serverTimestamp
     ck_assert_int_eq(dst.data[2], 0);
@@ -974,15 +948,14 @@ START_TEST(UA_DataValue_encodeShallWorkOnExampleWithVariant) {
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
     UA_ByteString dst = { 24, data };
-
-    UA_Int32  retval  = 0;
-    size_t pos     = 0;
+    UA_Byte *pos = dst.data;
+    const UA_Byte *end = &dst.data[dst.length];
 
     // when
-    retval = UA_DataValue_encodeBinary(&src, &dst, &pos);
+    UA_StatusCode retval = UA_DataValue_encodeBinary(&src, &pos, &end);
     // then
-    ck_assert_int_eq(pos, 1+(1+4)+8);           // represents the length
-    ck_assert_uint_eq(pos, UA_calcSizeBinary(&src, &UA_TYPES[UA_TYPES_DATAVALUE]));
+    ck_assert_int_eq((uintptr_t)(pos - dst.data), 1+(1+4)+8);           // represents the length
+    ck_assert_uint_eq(1+(1+4)+8, UA_calcSizeBinary(&src, &UA_TYPES[UA_TYPES_DATAVALUE]));
     ck_assert_int_eq(dst.data[0], 0x08 | 0x01); // encodingMask
     ck_assert_int_eq(dst.data[1], 0x06);        // Variant's Encoding Mask - INT32
     ck_assert_int_eq(dst.data[2], 45);          // the single value
@@ -1539,11 +1512,9 @@ static Suite *testSuite_builtin(void) {
     tcase_add_test(tc_copy, UA_Array_copyByteArrayShallWorkOnExample);
     tcase_add_test(tc_copy, UA_Array_copyUA_StringShallWorkOnExample);
     tcase_add_test(tc_copy, UA_ExtensionObject_copyShallWorkOnExample);
-
     tcase_add_test(tc_copy, UA_Variant_copyShallWorkOnSingleValueExample);
     tcase_add_test(tc_copy, UA_Variant_copyShallWorkOn1DArrayExample);
     tcase_add_test(tc_copy, UA_Variant_copyShallWorkOn2DArrayExample);
-
     tcase_add_test(tc_copy, UA_DiagnosticInfo_copyShallWorkOnExample);
     tcase_add_test(tc_copy, UA_ApplicationDescription_copyShallWorkOnExample);
     tcase_add_test(tc_copy, UA_QualifiedName_copyShallWorkOnInputExample);
@@ -1554,7 +1525,6 @@ static Suite *testSuite_builtin(void) {
     return s;
 }
 
-
 int main(void) {
     int      number_failed = 0;
     Suite   *s;

+ 10 - 8
tests/check_types_custom.c

@@ -90,13 +90,14 @@ START_TEST(parseCustomScalar) {
     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);
+    UA_Byte *pos = buf.data;
+    const UA_Byte *end = &buf.data[buf.length];
+    retval = UA_encodeBinary(&var, &UA_TYPES[UA_TYPES_VARIANT],
+                             &pos, &end, NULL, NULL);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 
     UA_Variant var2;
-    offset = 0;
+    size_t 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);
@@ -164,13 +165,14 @@ START_TEST(parseCustomArray) {
     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);
+    UA_Byte *pos = buf.data;
+    const UA_Byte *end = &buf.data[buf.length];
+    retval = UA_encodeBinary(&var, &UA_TYPES[UA_TYPES_VARIANT],
+                             &pos, &end, NULL, NULL);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 
     UA_Variant var2;
-    offset = 0;
+    size_t 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]);

+ 25 - 14
tests/check_types_memory.c

@@ -7,6 +7,7 @@
 #include <stdio.h>
 
 #include "ua_types.h"
+#include "ua_server.h"
 #include "ua_types_generated.h"
 #include "ua_types_generated_handling.h"
 #include "ua_types_encoding_binary.h"
@@ -62,12 +63,13 @@ START_TEST(encodeShallYieldDecode) {
 
     // given
     UA_ByteString msg1, msg2;
-    size_t pos = 0;
     void *obj1 = UA_new(&UA_TYPES[_i]);
     UA_StatusCode retval = UA_ByteString_allocBuffer(&msg1, 65000); // fixed buf size
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
-    retval = UA_encodeBinary(obj1, &UA_TYPES[_i], NULL, NULL, &msg1, &pos);
-    msg1.length = pos;
+    UA_Byte *pos = msg1.data;
+    const UA_Byte *end = &msg1.data[msg1.length];
+    retval = UA_encodeBinary(obj1, &UA_TYPES[_i],
+                             &pos, &end, NULL, NULL);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_delete(obj1, &UA_TYPES[_i]);
         UA_ByteString_deleteMembers(&msg1);
@@ -76,17 +78,21 @@ START_TEST(encodeShallYieldDecode) {
 
     // when
     void *obj2 = UA_new(&UA_TYPES[_i]);
-    pos = 0; retval = UA_decodeBinary(&msg1, &pos, obj2, &UA_TYPES[_i], 0, NULL); 
+    size_t offset = 0;
+    retval = UA_decodeBinary(&msg1, &offset, 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
     retval = UA_ByteString_allocBuffer(&msg2, 65000);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
-    pos = 0; retval = UA_encodeBinary(obj2, &UA_TYPES[_i], NULL, NULL, &msg2, &pos);
-    msg2.length = pos;
+    pos = msg2.data;
+    end = &msg2.data[msg2.length];
+    retval = UA_encodeBinary(obj2, &UA_TYPES[_i], &pos, &end, NULL, NULL);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 
     // then
+    msg1.length = offset;
+    msg2.length = offset;
     ck_assert_msg(UA_ByteString_equal(&msg1, &msg2) == true, "messages differ idx=%d,nodeid=%i", _i,
                   UA_TYPES[_i].typeId.identifier.numeric);
 
@@ -104,19 +110,23 @@ START_TEST(decodeShallFailWithTruncatedBufferButSurvive) {
     // given
     UA_ByteString msg1;
     void *obj1 = UA_new(&UA_TYPES[_i]);
-    size_t pos = 0;
     UA_StatusCode retval = UA_ByteString_allocBuffer(&msg1, 65000); // fixed buf size
-    retval |= UA_encodeBinary(obj1, &UA_TYPES[_i], NULL, NULL, &msg1, &pos);
+    UA_Byte *pos = msg1.data;
+    const UA_Byte *end = &msg1.data[msg1.length];
+    retval |= UA_encodeBinary(obj1, &UA_TYPES[_i], &pos, &end, NULL, NULL);
     UA_delete(obj1, &UA_TYPES[_i]);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_ByteString_deleteMembers(&msg1);
         return; // e.g. variants cannot be encoded after an init without failing (no datatype set)
     }
+
+    size_t half = (uintptr_t)(pos - msg1.data) / 2;
+    msg1.length = half;
+
     // when
     void *obj2 = UA_new(&UA_TYPES[_i]);
-    msg1.length = pos / 2;
-    pos = 0;
-    retval = UA_decodeBinary(&msg1, &pos, obj2, &UA_TYPES[_i], 0, NULL); 
+    size_t offset = 0;
+    retval = UA_decodeBinary(&msg1, &offset, obj2, &UA_TYPES[_i], 0, NULL); 
     ck_assert_int_ne(retval, UA_STATUSCODE_GOOD);
     UA_delete(obj2, &UA_TYPES[_i]);
     UA_ByteString_deleteMembers(&msg1);
@@ -205,12 +215,13 @@ START_TEST(calcSizeBinaryShallBeCorrect) {
     UA_ByteString msg;
     UA_StatusCode retval = UA_ByteString_allocBuffer(&msg, predicted_size);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
-    size_t offset = 0;
-    retval = UA_encodeBinary(obj, &UA_TYPES[_i], NULL, NULL, &msg, &offset);
+    UA_Byte *pos = msg.data;
+    const UA_Byte *end = &msg.data[msg.length];
+    retval = UA_encodeBinary(obj, &UA_TYPES[_i], &pos, &end, NULL, NULL);
     if(retval)
         printf("%i\n",_i);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
-    ck_assert_int_eq(offset, predicted_size);
+    ck_assert_int_eq((uintptr_t)(pos - msg.data), predicted_size);
     UA_delete(obj, &UA_TYPES[_i]);
     UA_ByteString_deleteMembers(&msg);
 }

+ 1 - 1
tools/generate_datatypes.py

@@ -143,7 +143,7 @@ class Type(object):
         return funcs
 
     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_encodeBinary(const UA_%s *src, UA_Byte **bufPos, const UA_Byte **bufEnd) {\n    return UA_encodeBinary(src, %s, bufPos, bufEnd, NULL, NULL);\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, 0, NULL);\n}"
         return enc % tuple(list(itertools.chain(*itertools.repeat([self.name, self.name, self.datatype_ptr()], 2))))